Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
252f1d1119 | ||
|
|
5a54950382 | ||
|
|
209b2b59e0 | ||
|
|
ed7db8a8c4 | ||
|
|
01f11c7de7 | ||
|
|
c8502bfa7f | ||
|
|
1044c009a4 | ||
|
|
d85345eb41 | ||
|
|
736dfb570a | ||
|
|
748d7a972e | ||
|
|
7b10d810bd | ||
|
|
af9556139b | ||
|
|
410f9c5d75 | ||
|
|
5f782bbc13 | ||
|
|
125d38c608 | ||
|
|
5276214773 | ||
|
|
74ed54bbcd | ||
|
|
b1c7dac2ce | ||
|
|
28ce4de343 | ||
|
|
c85ca879cc | ||
|
|
00c9d17786 | ||
|
|
532c94a0e0 | ||
|
|
8e7db90bbc | ||
|
|
841c638b62 | ||
|
|
81a8bb3dc9 | ||
|
|
0c0fde335e | ||
|
|
0f5da5fbe9 | ||
|
|
4b052de9fa | ||
|
|
60ccd48a59 | ||
|
|
3edf8f654b | ||
|
|
e7997f8093 | ||
|
|
e2aedfe1c0 | ||
|
|
83f0d63225 | ||
|
|
9d9b3ed478 |
+85
-30
@@ -9,7 +9,6 @@ using Windows.Management.Deployment;
|
||||
|
||||
namespace CrapFixer
|
||||
{
|
||||
|
||||
public class AppAnalysisResult
|
||||
{
|
||||
public string AppName { get; set; }
|
||||
@@ -43,13 +42,18 @@ namespace CrapFixer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes the apps based on predefined apps (from resources) and logs the results in MainForm.
|
||||
/// Analyzes the installed apps against provided bloatware patterns and whitelist,
|
||||
/// logs the results, and returns the matches.
|
||||
/// </summary>
|
||||
/// <param name="predefinedApps"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<AppAnalysisResult>> AnalyzeAndLogAppsAsync(string[] predefinedApps)
|
||||
/// <param name="bloatwarePatterns">List of bloatware keywords to check against</param>
|
||||
/// <param name="whitelistPatterns">List of app names to ignore</param>
|
||||
/// <param name="scanAll">If true, scans all apps regardless of bloatware patterns</param>
|
||||
public async Task<List<AppAnalysisResult>> AnalyzeAndLogAppsAsync(
|
||||
string[] bloatwarePatterns,
|
||||
string[] whitelistPatterns,
|
||||
bool scanAll)
|
||||
{
|
||||
var apps = await AnalyzeAppsAsync(predefinedApps);
|
||||
var apps = await AnalyzeAppsAsync(bloatwarePatterns, whitelistPatterns, scanAll);
|
||||
|
||||
if (apps.Count > 0)
|
||||
{
|
||||
@@ -64,37 +68,56 @@ namespace CrapFixer
|
||||
Logger.Log("✅ No Microsoft Store bloatware apps found.", LogLevel.Info);
|
||||
}
|
||||
|
||||
Logger.Log(""); // Add a blank line for spacing
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes the apps based on predefined apps (from resources) and returns matching apps.
|
||||
/// </summary>
|
||||
/// <param name="predefinedApps"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<AppAnalysisResult>> AnalyzeAppsAsync(string[] predefinedApps)
|
||||
public async Task<List<AppAnalysisResult>> AnalyzeAppsAsync(string[] bloatwarePatterns, string[] whitelistPatterns, bool scanAll = false)
|
||||
{
|
||||
Logger.Log("\n🧩 APPS ANALYSIS", LogLevel.Info);
|
||||
Logger.Log(new string('=', 50), LogLevel.Info);
|
||||
|
||||
await LoadAppsAsync(); // Load all apps before analysis
|
||||
await LoadAppsAsync(); // Load all installed apps
|
||||
|
||||
var result = new List<AppAnalysisResult>();
|
||||
|
||||
// Check each app's name against predefined patterns
|
||||
foreach (var app in _appDirectory)
|
||||
{
|
||||
foreach (string pattern in predefinedApps)
|
||||
string appName = app.Key.ToLower();
|
||||
|
||||
// Always skip whitelisted apps
|
||||
if (whitelistPatterns.Any(w => appName.Contains(w)))
|
||||
continue;
|
||||
|
||||
if (scanAll)
|
||||
{
|
||||
if (app.Key.ToLower().Contains(pattern.ToLower()))
|
||||
// If wildcard is set, include everything not whitelisted
|
||||
result.Add(new AppAnalysisResult
|
||||
{
|
||||
result.Add(new AppAnalysisResult
|
||||
AppName = app.Key,
|
||||
FullName = app.Value
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only match against provided patterns
|
||||
foreach (var pattern in bloatwarePatterns)
|
||||
{
|
||||
if (appName.Contains(pattern))
|
||||
{
|
||||
AppName = app.Key,
|
||||
FullName = app.Value // Store the full name
|
||||
});
|
||||
break;
|
||||
result.Add(new AppAnalysisResult
|
||||
{
|
||||
AppName = app.Key,
|
||||
FullName = app.Value
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,39 +194,71 @@ namespace CrapFixer
|
||||
return removedApps; // Return removed apps to update the UI
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Loads an external bloatware list from the CFEnhancer text file (comma-separated).
|
||||
/// Falls back to an empty array if the file doesn't exist or fails to load.
|
||||
/// Loads external bloatware and whitelist patterns from a text file (e.g., CFEnhancer.txt).
|
||||
/// Also checks if wildcard (*) is set to scan all apps.
|
||||
/// </summary>
|
||||
public string[] LoadExternalBloatwareList(string fileName = "CFEnhancer.txt")
|
||||
/// <param name="fileName">Name of the file to load from (must be in Plugins folder)</param>
|
||||
/// <returns>
|
||||
/// A tuple containing:
|
||||
/// - bloatwarePatterns: List of apps to flag as bloatware
|
||||
/// - whitelistPatterns: List of apps to ignore/exclude from detection
|
||||
/// - scanAll: Whether all apps should be shown regardless of matching patterns
|
||||
/// </returns>
|
||||
public (string[] bloatwarePatterns, string[] whitelistPatterns, bool scanAll) LoadExternalBloatwarePatterns(string fileName = "CFEnhancer.txt")
|
||||
{
|
||||
try
|
||||
{
|
||||
string exeDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
string pluginsDir = Path.Combine(exeDir, "plugins");
|
||||
string fullPath = Path.Combine(pluginsDir, fileName);
|
||||
string fullPath = Path.Combine(exeDir, "Plugins", fileName);
|
||||
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
Logger.Log($"⚠️ The bloatware radar stays basic for now 🧠. Get the CFEnhancer detection list from Options > Plugins ", LogLevel.Warning);
|
||||
return Array.Empty<string>();
|
||||
Logger.Log($"⚠️ The bloatware radar stays basic for now 🧠. Get the enhanced detection list from Options > Plugins > CFEnhancer plugin", LogLevel.Warning);
|
||||
return (Array.Empty<string>(), Array.Empty<string>(), false);
|
||||
}
|
||||
|
||||
var content = File.ReadAllText(fullPath);
|
||||
return content.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(s => s.Trim())
|
||||
.ToArray();
|
||||
var lines = File.ReadAllLines(fullPath);
|
||||
var bloatware = new List<string>(); // Apps to detect as bloatware
|
||||
var whitelist = new List<string>(); // Apps to ignore completely
|
||||
bool scanAll = false; // Set to true if wildcard (*) is present
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
// Strip comments after "#" and trim whitespace
|
||||
var entry = line.Split('#')[0].Trim();
|
||||
|
||||
// Skip empty lines or lines with only comments
|
||||
if (string.IsNullOrWhiteSpace(entry))
|
||||
continue;
|
||||
|
||||
// Wildcard entry means: show all installed apps
|
||||
if (entry == "*" || entry == "*.*")
|
||||
{
|
||||
scanAll = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Entries starting with "!" go to the whitelist (excluded apps)
|
||||
if (entry.StartsWith("!"))
|
||||
whitelist.Add(entry.Substring(1).Trim().ToLower());
|
||||
else
|
||||
bloatware.Add(entry.ToLower()); // All other entries are bloatware patterns
|
||||
}
|
||||
|
||||
return (bloatware.ToArray(), whitelist.ToArray(), scanAll);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Error reading external bloatware file: {ex.Message}", LogLevel.Warning);
|
||||
return Array.Empty<string>();
|
||||
return (Array.Empty<string>(), Array.Empty<string>(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// OPTIONALLY!Returns all installed apps in the system.
|
||||
/// OPTIONALLY!Returns all installed apps in the system.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<AppAnalysisResult>> GetAllInstalledAppsAsync()
|
||||
|
||||
+18
-7
@@ -7,7 +7,7 @@
|
||||
<ProjectGuid>{FA7D5C89-63D3-4AF0-80C2-D650D35E575B}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>CFixer</RootNamespace>
|
||||
<AssemblyName>CFixer</AssemblyName>
|
||||
<AssemblyName>Crap Fixer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
@@ -57,7 +57,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AppManagerService.cs" />
|
||||
<Compile Include="Features\AI\AskCopilot.cs" />
|
||||
<Compile Include="Features\AI\ClickToDo.cs" />
|
||||
<Compile Include="Features\FeatureManager.cs" />
|
||||
<Compile Include="Features\Edge\BrowserSignin.cs" />
|
||||
<Compile Include="Features\Edge\DefaultTopSites.cs" />
|
||||
@@ -78,6 +78,7 @@
|
||||
<Compile Include="Features\System\SpeedUpShutdown.cs" />
|
||||
<Compile Include="Features\System\SystemResponsiveness.cs" />
|
||||
<Compile Include="Features\System\TaskbarEndTask.cs" />
|
||||
<Compile Include="Features\UI\BingSearch.cs" />
|
||||
<Compile Include="Features\UI\DarkMode.cs" />
|
||||
<Compile Include="Features\UI\SearchBoxSuggestions.cs" />
|
||||
<Compile Include="Features\UI\SnapAssistFlyout.cs" />
|
||||
@@ -128,6 +129,11 @@
|
||||
<Compile Include="Features\UI\ShowTaskViewButton.cs" />
|
||||
<Compile Include="Features\UI\StartLayout.cs" />
|
||||
<Compile Include="Features\UI\TaskbarAlignment.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\AboutView.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
@@ -152,6 +158,12 @@
|
||||
<Compile Include="Views\OptionsView.Designer.cs">
|
||||
<DependentUpon>OptionsView.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\ViveView.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Views\ViveView.Designer.cs">
|
||||
<DependentUpon>ViveView.cs</DependentUpon>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="MainForm.resx">
|
||||
<DependentUpon>MainForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
@@ -162,6 +174,7 @@
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Views\AboutView.resx">
|
||||
<DependentUpon>AboutView.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Views\PluginsView.resx">
|
||||
<DependentUpon>PluginsView.cs</DependentUpon>
|
||||
@@ -172,17 +185,15 @@
|
||||
<EmbeddedResource Include="Views\OptionsView.resx">
|
||||
<DependentUpon>OptionsView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Views\ViveView.resx">
|
||||
<DependentUpon>ViveView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.manifest" />
|
||||
<Compile Include="Features\FeatureLoader.cs" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using CrapFixer;
|
||||
|
||||
namespace Settings.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Disables the Click to Do feature, which also removes its entry from the right-click context menu.
|
||||
/// Only available on Copilot+ PCs running Windows 11 24H2 or newer.
|
||||
/// Requires a PC with an NPU (Neural Processing Unit).
|
||||
/// </summary>
|
||||
internal class ClickToDo: FeatureBase
|
||||
{
|
||||
private const string keyName = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\ClickToDo";
|
||||
private const string valueName = "DisableClickToDo";
|
||||
private const int recommendedValue = 1; // 1 = fully disabled, including context menu
|
||||
|
||||
public override string GetFeatureDetails()
|
||||
{
|
||||
return $"{keyName} | Value: {valueName} | Set to: {recommendedValue} (disables Click to Do, removing it from context menus). " +
|
||||
"Note: This setting only applies on Copilot+ PCs with Windows 11 24H2 or newer.";
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override string ID()
|
||||
{
|
||||
return "Disable Click to Do (Only Copilot+ PCs)";
|
||||
}
|
||||
|
||||
public override string Info()
|
||||
{
|
||||
return "Disables Click to Do entirely, including its context menu entry which uses on-device AI to suggest actions based on screen content. Only available on Copilot+ PCs with Windows 11 24H2 or newer.";
|
||||
}
|
||||
|
||||
public override Task<bool> CheckFeature()
|
||||
{
|
||||
return Task.FromResult(Utils.IntEquals(keyName, valueName, recommendedValue));
|
||||
}
|
||||
|
||||
public override Task<bool> DoFeature()
|
||||
{
|
||||
try
|
||||
{
|
||||
Registry.SetValue(keyName, valueName, recommendedValue, RegistryValueKind.DWord);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log("Error disabling Click to Do: " + ex.Message, LogLevel.Error);
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool UndoFeature()
|
||||
{
|
||||
try
|
||||
{
|
||||
Registry.SetValue(keyName, valueName, 0, RegistryValueKind.DWord);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log("Error re-enabling Click to Do: " + ex.Message, LogLevel.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using Settings.Issues;
|
||||
using Settings.Ads;
|
||||
using Settings.Ads;
|
||||
using Settings.AI;
|
||||
using Settings.Edge;
|
||||
using Settings.Gaming;
|
||||
using Settings.Issues;
|
||||
using Settings.Personalization;
|
||||
using Settings.Privacy;
|
||||
using Settings.System;
|
||||
using System.Collections.Generic;
|
||||
using Settings.UI;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Features
|
||||
{
|
||||
@@ -69,6 +69,7 @@ namespace Features
|
||||
new FeatureNode(new ShowOrHideMostUsedApps()),
|
||||
new FeatureNode(new ShowTaskViewButton()),
|
||||
new FeatureNode(new DisableSearchBoxSuggestions()),
|
||||
new FeatureNode(new DisableBingSearch()),
|
||||
new FeatureNode(new StartLayout()),
|
||||
new FeatureNode(new TaskbarAlignment()),
|
||||
new FeatureNode(new Transparency()),
|
||||
@@ -121,7 +122,7 @@ namespace Features
|
||||
{
|
||||
new FeatureNode(new CopilotTaskbar()),
|
||||
new FeatureNode(new Recall()),
|
||||
new FeatureNode(new AskCopilot()),
|
||||
new FeatureNode(new ClickToDo()) { DefaultChecked = false },
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Features;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
@@ -16,12 +17,14 @@ namespace CrapFixer
|
||||
|
||||
// Public properties to access the analysis results
|
||||
public static int TotalChecked => totalChecked;
|
||||
|
||||
public static int IssuesFound => issuesFound;
|
||||
|
||||
public static void ResetAnalysis()
|
||||
{
|
||||
totalChecked = 0;
|
||||
issuesFound = 0;
|
||||
Logger.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -29,6 +32,9 @@ namespace CrapFixer
|
||||
/// </summary>
|
||||
public static void LoadFeatures(TreeView tree)
|
||||
{
|
||||
// Hide the TreeView to avoid flickering and visible scroll jump
|
||||
tree.Visible = false;
|
||||
|
||||
var features = FeatureLoader.Load();
|
||||
tree.Nodes.Clear();
|
||||
|
||||
@@ -43,6 +49,14 @@ namespace CrapFixer
|
||||
}
|
||||
|
||||
tree.ExpandAll(); // expand all nodes
|
||||
|
||||
// Set scroll to top and make TreeView visible
|
||||
tree.BeginInvoke(new Action(() =>
|
||||
{
|
||||
// Ensure the first node is shown at the top (prevents auto-scroll to bottom)
|
||||
if (tree.Nodes.Count > 0) tree.TopNode = tree.Nodes[0];
|
||||
tree.Visible = true;
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -166,52 +180,75 @@ namespace CrapFixer
|
||||
RestoreChecked(child);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes a selected feature and logs its status.
|
||||
/// Analyzes a selected feature or, if it's a category, analyzes only checked child features.
|
||||
/// </summary>
|
||||
public static async void AnalyzeFeature(TreeNode node)
|
||||
{
|
||||
// no && node.Checked
|
||||
// Analyze this node if it's a leaf node (not a category)
|
||||
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
|
||||
{
|
||||
bool isOk = await fn.Feature.CheckFeature();
|
||||
node.ForeColor = isOk ? Color.Gray : Color.Red;
|
||||
|
||||
Logger.Log(isOk
|
||||
? $"✅ Feature: {fn.Name} is properly configured."
|
||||
: $"❌ Feature: {fn.Name} requires attention.\n ➤ {fn.Feature.GetFeatureDetails()}",
|
||||
isOk ? LogLevel.Info : LogLevel.Warning);
|
||||
|
||||
if (!isOk)
|
||||
if (isOk)
|
||||
{
|
||||
Logger.Log($"✅ Feature: {fn.Name} is properly configured.", LogLevel.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
string category = node.Parent?.Text ?? "General";
|
||||
Logger.Log($"❌ Feature: {fn.Name} requires attention.", LogLevel.Warning);
|
||||
Logger.Log($" ➤ {fn.Feature.GetFeatureDetails()}");
|
||||
Logger.Log(new string('-', 50), LogLevel.Info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's a category node, analyze only checked child nodes
|
||||
foreach (TreeNode child in node.Nodes)
|
||||
{
|
||||
if (child.Checked)
|
||||
AnalyzeFeature(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to fix the selected feature and logs the result.
|
||||
/// Attempts to fix the selected feature or, if it is a category, fixes only checked child features.
|
||||
/// </summary>
|
||||
public static async Task FixFeature(TreeNode node)
|
||||
{
|
||||
// no && node.Checked
|
||||
// Try to fix this node if it is NOT a category (i.e., a leaf node)
|
||||
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
|
||||
{
|
||||
// Always fix the selected leaf node, regardless of Checked
|
||||
bool result = await fn.Feature.DoFeature();
|
||||
Logger.Log(result
|
||||
? $"🔧 {fn.Name} - Fixed"
|
||||
: $"❌ {fn.Name} - ⚠️ Fix failed (This feature may require admin privileges)",
|
||||
result ? LogLevel.Info : LogLevel.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's a category node, fix only checked child nodes (recursively)
|
||||
foreach (TreeNode child in node.Nodes)
|
||||
{
|
||||
if (child.Checked)
|
||||
await FixFeature(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Restores the selected feature to its original state and logs the result.
|
||||
/// Restores a selected feature (always) or, if it's a category, only restores checked child features.
|
||||
/// Logs success or failure.
|
||||
/// </summary>
|
||||
public static void RestoreFeature(TreeNode node)
|
||||
{
|
||||
// no && node.Checked
|
||||
// Restore feature node regardless of Checked state
|
||||
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
|
||||
{
|
||||
bool ok = fn.Feature.UndoFeature();
|
||||
@@ -220,38 +257,26 @@ namespace CrapFixer
|
||||
: $"❌ {fn.Name} - Restore failed",
|
||||
ok ? LogLevel.Info : LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively previews changes for all checked features.
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
public static void PreviewChanges(TreeNode node)
|
||||
{
|
||||
if (node.Tag is FeatureNode fn)
|
||||
else
|
||||
{
|
||||
if (!fn.IsCategory && fn.Feature != null)
|
||||
{
|
||||
string details = fn.Feature.GetFeatureDetails();
|
||||
|
||||
string category = node.Parent?.Text ?? "General";
|
||||
Logger.Log($"🛈 [PREVIEW] [{category}] {fn.Name}", LogLevel.Info);
|
||||
Logger.Log($" ➤ {details}");
|
||||
Logger.Log(new string('-', 50), LogLevel.Info);
|
||||
}
|
||||
|
||||
// For category nodes, only restore checked children
|
||||
foreach (TreeNode child in node.Nodes)
|
||||
PreviewChanges(child);
|
||||
{
|
||||
if (child.Checked)
|
||||
RestoreFeature(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Displays help information for the selected feature.
|
||||
/// Displays help information for the selected feature or plugin.
|
||||
/// If a feature is selected, also offers to search online.
|
||||
/// </summary>
|
||||
public static void ShowHelp(TreeNode node)
|
||||
{
|
||||
if (node.Tag is FeatureNode fn && fn.Feature != null)
|
||||
// Show help for features
|
||||
if (node?.Tag is FeatureNode fn && fn.Feature != null)
|
||||
{
|
||||
string info = fn.Feature.Info();
|
||||
MessageBox.Show(
|
||||
@@ -259,27 +284,36 @@ namespace CrapFixer
|
||||
$"Help: {fn.Name}",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Information);
|
||||
|
||||
// Optional online help
|
||||
var result = MessageBox.Show(
|
||||
"Would you like to search online for more information about this feature?",
|
||||
"Online Help",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
string searchQuery = Uri.EscapeDataString(fn.Feature.GetFeatureDetails());
|
||||
string webUrl = $"https://www.google.com/search?q={searchQuery}";
|
||||
System.Diagnostics.Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = webUrl,
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
// Show help for plugins
|
||||
if (!PluginManager.ShowHelp(node))
|
||||
{
|
||||
MessageBox.Show("⚠️ No feature selected or feature is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
MessageBox.Show("⚠️ No feature or plugin selected, or help info unavailable.",
|
||||
"Help",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the default web browser to search for help online for the selected feature (Extended ShowHelp).
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
public static void ShowHelpOnline(TreeNode node)
|
||||
{
|
||||
if (node?.Tag is FeatureNode fn)
|
||||
{
|
||||
string searchQuery = Uri.EscapeDataString( fn.Feature.GetFeatureDetails());
|
||||
string webUrl = $"microsoft-edge:https://www.google.com/search?q={searchQuery}";
|
||||
|
||||
System.Diagnostics.Process.Start(webUrl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ namespace Settings.Issues
|
||||
var totalSize = GetDirectorySize(tempPath);
|
||||
|
||||
bool isOk = totalSize <= 50;
|
||||
|
||||
|
||||
return Task.FromResult(isOk);
|
||||
}
|
||||
@@ -34,13 +33,12 @@ namespace Settings.Issues
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override string GetFeatureDetails()
|
||||
{
|
||||
try
|
||||
{
|
||||
var totalSize = GetDirectorySize(tempPath);
|
||||
return $"Temp folder size: {totalSize} MB (We need also to include cleanmgr in the next run)";
|
||||
return $"Temp folder size: {totalSize} MB (including cleanmgr /sagerun:1 in the next run)";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -53,7 +51,7 @@ namespace Settings.Issues
|
||||
{
|
||||
try
|
||||
{
|
||||
await CleanTempFolderAsync();
|
||||
await CleanTempFolderAsync();
|
||||
await RunDiskCleanup();
|
||||
Logger.Log("Basic Cleanup completed successfully.", LogLevel.Info);
|
||||
return true;
|
||||
@@ -65,7 +63,6 @@ namespace Settings.Issues
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task CleanTempFolderAsync()
|
||||
{
|
||||
var files = await Task.Run(() => Directory.GetFiles(tempPath, "*", SearchOption.AllDirectories));
|
||||
@@ -75,7 +72,7 @@ namespace Settings.Issues
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Run(() => File.Delete(file));
|
||||
await Task.Run(() => File.Delete(file));
|
||||
Logger.Log($"Deleted file: {file}", LogLevel.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -98,7 +95,6 @@ namespace Settings.Issues
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// calculate the size of the directory in MB
|
||||
private long GetDirectorySize(string directory)
|
||||
{
|
||||
@@ -110,7 +106,6 @@ namespace Settings.Issues
|
||||
// Calculate size of all files
|
||||
size += directoryInfo.GetFiles("*", SearchOption.AllDirectories).Sum(file => file.Length);
|
||||
|
||||
|
||||
return size / (1024 * 1024); // return size in MB
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -144,13 +139,13 @@ namespace Settings.Issues
|
||||
using (var process1 = Process.Start(startInfo1))
|
||||
{
|
||||
if (process1 != null)
|
||||
await Task.Run(() => process1.WaitForExit());
|
||||
await Task.Run(() => process1.WaitForExit());
|
||||
}
|
||||
|
||||
using (var process2 = Process.Start(startInfo2))
|
||||
{
|
||||
if (process2 != null)
|
||||
await Task.Run(() => process2.WaitForExit());
|
||||
await Task.Run(() => process2.WaitForExit());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -159,8 +154,7 @@ namespace Settings.Issues
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Undo method: Cleanup cannot be undone, so return false
|
||||
public override bool UndoFeature() => false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using CrapFixer;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Threading.Tasks;
|
||||
using CrapFixer;
|
||||
|
||||
namespace Settings.System
|
||||
{
|
||||
@@ -29,9 +30,9 @@ namespace Settings.System
|
||||
|
||||
try
|
||||
{
|
||||
string output = await ExecuteCommand("winget upgrade --include-unknown");
|
||||
string output = await ExecuteCommand("winget upgrade --include-unknown" );
|
||||
|
||||
Logger.Log("Winget upgrade check:\n" + output, LogLevel.Info);
|
||||
Logger.Log("Winget upgrade check:\n" + output, LogLevel.Info, new Font("Cascadia Mono", 8.25f));
|
||||
|
||||
return output.ToLower().Contains("available");
|
||||
}
|
||||
@@ -122,4 +123,4 @@ namespace Settings.System
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using CrapFixer;
|
||||
|
||||
namespace Settings.UI
|
||||
{
|
||||
internal class DisableBingSearch : FeatureBase
|
||||
{
|
||||
private const string keyName = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Search";
|
||||
private const string valueName = "BingSearchEnabled";
|
||||
private const int recommendedValue = 0;
|
||||
|
||||
public override string GetFeatureDetails()
|
||||
{
|
||||
return $"{keyName} | Value: {valueName} | Recommended Value: {recommendedValue}";
|
||||
}
|
||||
|
||||
public override string ID()
|
||||
{
|
||||
return "Disable Bing Search";
|
||||
}
|
||||
|
||||
public override string Info()
|
||||
{
|
||||
return "This feature disables Bing integration in Windows Search.";
|
||||
}
|
||||
|
||||
public override Task<bool> CheckFeature()
|
||||
{
|
||||
return Task.FromResult(Utils.IntEquals(keyName, valueName, recommendedValue));
|
||||
}
|
||||
|
||||
public override Task<bool> DoFeature()
|
||||
{
|
||||
try
|
||||
{
|
||||
Registry.SetValue(keyName, valueName, recommendedValue, RegistryValueKind.DWord);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log("Error in DisableBingSearch: " + ex.Message, LogLevel.Error);
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool UndoFeature()
|
||||
{
|
||||
try
|
||||
{
|
||||
Registry.SetValue(keyName, valueName, 1, RegistryValueKind.DWord);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log("Error undoing DisableBingSearch: " + ex.Message, LogLevel.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,25 +7,37 @@ using System.Windows.Forms;
|
||||
/// </summary>
|
||||
public static class Logger
|
||||
{
|
||||
/// <summary>
|
||||
/// The RichTextBox control to which log messages are written.
|
||||
/// </summary>
|
||||
public static RichTextBox OutputBox;
|
||||
|
||||
private static readonly Font DefaultFont = new Font("Consolas", 8.25f, FontStyle.Regular);
|
||||
private static readonly Font DefaultFont = new Font("Tahoma", 8.25f, FontStyle.Regular);
|
||||
|
||||
public static void Log(string message, LogLevel level = LogLevel.Info)
|
||||
/// <summary>
|
||||
/// Writes a message with an optional log level and custom font.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to display.</param>
|
||||
/// <param name="level">The log level (e.g., Info, Warning, Error).</param>
|
||||
/// <param name="customFont">An optional font for the message.</param>
|
||||
public static void Log(string message, LogLevel level = LogLevel.Info, Font customFont = null)
|
||||
{
|
||||
if (OutputBox == null) return;
|
||||
|
||||
if (OutputBox.InvokeRequired)
|
||||
{
|
||||
OutputBox.Invoke(new Action(() => LogInternal(message, level)));
|
||||
OutputBox.Invoke(new Action(() => LogInternal(message, level, customFont)));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogInternal(message, level);
|
||||
LogInternal(message, level, customFont);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LogInternal(string message, LogLevel level)
|
||||
/// <summary>
|
||||
/// Internal method to append text to the RichTextBox with formatting.
|
||||
/// </summary>
|
||||
private static void LogInternal(string message, LogLevel level, Font customFont = null)
|
||||
{
|
||||
// string prefix = $"[{DateTime.Now:HH:mm:ss}] [{level}] ";
|
||||
string fullMessage = message + Environment.NewLine;
|
||||
@@ -51,10 +63,11 @@ public static class Logger
|
||||
break;
|
||||
}
|
||||
|
||||
// Append text with color
|
||||
// Append formatted message
|
||||
OutputBox.SelectionStart = OutputBox.TextLength;
|
||||
OutputBox.SelectionLength = 0;
|
||||
OutputBox.SelectionColor = color;
|
||||
OutputBox.SelectionFont = customFont ?? DefaultFont; // use custom font if provided, otherwise use default
|
||||
OutputBox.AppendText(fullMessage);
|
||||
|
||||
// Reset selection to default
|
||||
@@ -62,8 +75,29 @@ public static class Logger
|
||||
OutputBox.SelectionFont = DefaultFont; // reset font
|
||||
OutputBox.ScrollToCaret(); // scroll to the end
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the log output.
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
if (OutputBox == null || OutputBox.IsDisposed)
|
||||
return;
|
||||
|
||||
if (OutputBox.InvokeRequired)
|
||||
{
|
||||
OutputBox.Invoke(new Action(Clear));
|
||||
return;
|
||||
}
|
||||
|
||||
OutputBox.Clear();
|
||||
OutputBox.SelectionColor = Color.Black;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log level types used to define message severity.
|
||||
/// </summary>
|
||||
public enum LogLevel
|
||||
{
|
||||
Info,
|
||||
|
||||
+46
-20
@@ -1,9 +1,9 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Management.Automation;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
|
||||
// This file is part of CFixer.
|
||||
namespace OSHelper
|
||||
{
|
||||
internal class OSHelper
|
||||
@@ -14,37 +14,63 @@ namespace OSHelper
|
||||
{
|
||||
try
|
||||
{
|
||||
using (PowerShell powerShellInstance = PowerShell.Create())
|
||||
using (PowerShell ps = PowerShell.Create())
|
||||
{
|
||||
powerShellInstance.AddScript("Get-CimInstance -ClassName Win32_OperatingSystem");
|
||||
Collection<PSObject> psOutput = powerShellInstance.Invoke();
|
||||
ps.AddScript("Get-CimInstance -ClassName Win32_OperatingSystem");
|
||||
var results = ps.Invoke();
|
||||
|
||||
foreach (PSObject outputItem in psOutput)
|
||||
foreach (var result in results)
|
||||
{
|
||||
if (outputItem != null)
|
||||
{
|
||||
string productName = outputItem.Properties["Caption"]?.Value?.ToString();
|
||||
if (!string.IsNullOrEmpty(productName))
|
||||
{
|
||||
string osVersion = productName.Contains("Windows 10") ? "Windows 10" : "Windows 11";
|
||||
if (result == null) continue;
|
||||
|
||||
using (RegistryKey displayVersionKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
|
||||
string caption = result.Properties["Caption"]?.Value?.ToString();
|
||||
string version = result.Properties["Version"]?.Value?.ToString();
|
||||
string build = result.Properties["BuildNumber"]?.Value?.ToString();
|
||||
|
||||
string displayVersion = Registry.GetValue(
|
||||
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion",
|
||||
"DisplayVersion", "")?.ToString();
|
||||
|
||||
// UBR = Update Build Revision
|
||||
string ubr = Registry.GetValue(
|
||||
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion",
|
||||
"UBR", 0)?.ToString();
|
||||
|
||||
bool isInsider = false;
|
||||
string ring = null;
|
||||
|
||||
using (var insiderKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\UpdateOrchestrator"))
|
||||
{
|
||||
if (insiderKey != null)
|
||||
{
|
||||
object enabled = insiderKey.GetValue("EnableInsiderBuilds");
|
||||
if (enabled != null && Convert.ToInt32(enabled) == 1)
|
||||
{
|
||||
if (displayVersionKey != null)
|
||||
{
|
||||
string displayVersion = displayVersionKey.GetValue("DisplayVersion")?.ToString();
|
||||
return $"{osVersion} ({displayVersion})";
|
||||
}
|
||||
isInsider = true;
|
||||
ring = insiderKey.GetValue("Ring")?.ToString();
|
||||
}
|
||||
return osVersion;
|
||||
}
|
||||
}
|
||||
|
||||
string osName = caption?.Contains("Windows 11") == true ? "Windows 11" :
|
||||
caption?.Contains("Windows 10") == true ? "Windows 10" :
|
||||
caption ?? "Unknown OS";
|
||||
|
||||
string fullBuild = !string.IsNullOrEmpty(build) && !string.IsNullOrEmpty(ubr)
|
||||
? $"{build}.{ubr}"
|
||||
: build ?? "unknown";
|
||||
|
||||
string insiderInfo = isInsider ? $" (Insider: {ring})" : "";
|
||||
|
||||
return $"{osName} {displayVersion}{insiderInfo} (Build {fullBuild})";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"OS info unavailable: {ex.Message}";
|
||||
}
|
||||
|
||||
return "OS not supported";
|
||||
});
|
||||
}
|
||||
|
||||
+33
-26
@@ -3,55 +3,65 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
// This file is part of CFixer.
|
||||
namespace CrapFixer
|
||||
{
|
||||
internal class Utils
|
||||
internal static class Utils
|
||||
{
|
||||
private const string GitHubUrl = "https://github.com/builtbybel/CrapFixer";
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a registry value is equal to a specified integer.
|
||||
/// Checks if a registry value equals a specified integer.
|
||||
/// </summary>
|
||||
/// <param name="keyName"></param>
|
||||
/// <param name="valueName"></param>
|
||||
/// <param name="expectedValue"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IntEquals(string keyName, string valueName, int expectedValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = Registry.GetValue(keyName, valueName, null);
|
||||
return (value != null && (int)value == expectedValue);
|
||||
object value = Registry.GetValue(keyName, valueName, null);
|
||||
return value is int intValue && intValue == expectedValue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
{
|
||||
MessageBox.Show(keyName, ex.Message, MessageBoxButtons.OK);
|
||||
Logger.Log($"Registry check failed for {keyName}\\{valueName}: {ex.Message}", LogLevel.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a registry value is equal to a specified string.
|
||||
/// Checks if a registry value equals a specified string.
|
||||
/// </summary>
|
||||
/// <param name="keyName"></param>
|
||||
/// <param name="valueName"></param>
|
||||
/// <param name="expectedValue"></param>
|
||||
/// <returns></returns>
|
||||
public static bool StringEquals(string keyName, string valueName, string expectedValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = Registry.GetValue(keyName, valueName, null);
|
||||
|
||||
return (value != null && (string)value == expectedValue);
|
||||
object value = Registry.GetValue(keyName, valueName, null);
|
||||
return value is string strValue && strValue == expectedValue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(keyName, ex.Message, MessageBoxButtons.OK);
|
||||
Logger.Log($"Registry check failed for {keyName}\\{valueName}: {ex.Message}", LogLevel.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the GitHub project page in the default browser.
|
||||
/// </summary>
|
||||
public static void OpenGitHubPage(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = GitHubUrl,
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Failed to open GitHub page: {ex.Message}", LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restarts Windows Explorer to apply UI changes.
|
||||
/// </summary>
|
||||
@@ -61,22 +71,19 @@ namespace CrapFixer
|
||||
{
|
||||
Logger.Log("Restarting Windows Explorer to apply UI changes...", LogLevel.Info);
|
||||
|
||||
// Kill all explorer instances
|
||||
foreach (var process in Process.GetProcessesByName("explorer"))
|
||||
{
|
||||
process.Kill();
|
||||
process.WaitForExit();
|
||||
}
|
||||
|
||||
// Restart explorer
|
||||
Process.Start("explorer.exe");
|
||||
|
||||
Logger.Log("Explorer restarted successfully. Changes should now be visible.", LogLevel.Info);
|
||||
Logger.Log("Explorer restarted successfully.", LogLevel.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log("Failed to restart Explorer: " + ex.Message, LogLevel.Error);
|
||||
Logger.Log($"Failed to restart Explorer: {ex.Message}", LogLevel.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+82
-22
@@ -27,7 +27,9 @@ public static class IniStateManager
|
||||
lines.Add("[APP]");
|
||||
lines.Add($"Width={form.Width}");
|
||||
lines.Add($"Height={form.Height}");
|
||||
lines.Add(""); // empty line for spacing
|
||||
lines.Add($"Top={form.Top}");
|
||||
lines.Add($"Left={form.Left}");
|
||||
// lines.Add(""); // empty line for spacing
|
||||
|
||||
// Append new FEATURES section (TreeView nodes states)
|
||||
lines.Add("[FEATURES]");
|
||||
@@ -62,8 +64,75 @@ public static class IniStateManager
|
||||
}
|
||||
}
|
||||
|
||||
// Loads global states (App size, TreeView nodes states) from the INI file
|
||||
public static void Load(TreeView tree, Form form)
|
||||
// Loads the global states (App size, TreeView nodes states) if enabled
|
||||
public static void LoadFeaturesIfEnabled(TreeView tree)
|
||||
{
|
||||
if (IsViewSettingEnabled("SETTINGS", "checkSaveToINI"))
|
||||
LoadFeatureStates(tree);
|
||||
}
|
||||
|
||||
public static void ApplyWindowState(Form form)
|
||||
{
|
||||
if (File.Exists(IniPath))
|
||||
{
|
||||
// Load window size and position from INI file
|
||||
LoadWindowState(form);
|
||||
form.StartPosition = FormStartPosition.Manual;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If INI file doesn't exist, set default position
|
||||
form.StartPosition = FormStartPosition.CenterScreen;
|
||||
}
|
||||
}
|
||||
|
||||
// Loads only the window size and position from the INI file
|
||||
public static void LoadWindowState(Form form)
|
||||
{
|
||||
if (!File.Exists(IniPath)) return;
|
||||
|
||||
var lines = File.ReadAllLines(IniPath);
|
||||
var section = "";
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var trimmed = line.Trim();
|
||||
if (string.IsNullOrWhiteSpace(trimmed)) continue;
|
||||
|
||||
// Check if line is a section header
|
||||
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
|
||||
{
|
||||
section = trimmed;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (section == "[APP]")
|
||||
{
|
||||
// Split line into key and value
|
||||
var parts = trimmed.Split(new[] { '=' }, 2);
|
||||
if (parts.Length != 2) continue;
|
||||
|
||||
var key = parts[0].Trim();
|
||||
var value = parts[1].Trim();
|
||||
|
||||
// Parse and apply window size and position
|
||||
if (int.TryParse(value, out int size))
|
||||
{
|
||||
if (key.Equals("Width", StringComparison.OrdinalIgnoreCase))
|
||||
form.Width = size;
|
||||
else if (key.Equals("Height", StringComparison.OrdinalIgnoreCase))
|
||||
form.Height = size;
|
||||
else if (key.Equals("Top", StringComparison.OrdinalIgnoreCase))
|
||||
form.Top = size;
|
||||
else if (key.Equals("Left", StringComparison.OrdinalIgnoreCase))
|
||||
form.Left = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loads only the feature states (TreeView node checked states) from the INI file
|
||||
public static void LoadFeatureStates(TreeView tree)
|
||||
{
|
||||
if (!File.Exists(IniPath)) return;
|
||||
|
||||
@@ -76,37 +145,28 @@ public static class IniStateManager
|
||||
var trimmed = line.Trim();
|
||||
if (string.IsNullOrWhiteSpace(trimmed)) continue;
|
||||
|
||||
// Check if line is a section
|
||||
// Check if line is a section header
|
||||
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
|
||||
{
|
||||
section = trimmed;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split line into key and value
|
||||
var parts = trimmed.Split(new[] { '=' }, 2);
|
||||
if (parts.Length != 2) continue;
|
||||
|
||||
var key = parts[0].Trim();
|
||||
var value = parts[1].Trim();
|
||||
|
||||
if (section == "[FEATURES]")
|
||||
{
|
||||
// Split line into key and value
|
||||
var parts = trimmed.Split(new[] { '=' }, 2);
|
||||
if (parts.Length != 2) continue;
|
||||
|
||||
var key = parts[0].Trim();
|
||||
var value = parts[1].Trim();
|
||||
|
||||
// Save checked state for each feature node
|
||||
states[key] = value.ToLower() == "true";
|
||||
}
|
||||
else if (section == "[APP]")
|
||||
{
|
||||
if (int.TryParse(value, out int size))
|
||||
{
|
||||
if (key.Equals("Width", StringComparison.OrdinalIgnoreCase))
|
||||
form.Width = size;
|
||||
else if (key.Equals("Height", StringComparison.OrdinalIgnoreCase))
|
||||
form.Height = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply saved feature states to tree nodes
|
||||
// Apply saved feature states to the TreeView nodes recursively
|
||||
ApplyStates(tree.Nodes, states);
|
||||
}
|
||||
|
||||
|
||||
Generated
+131
-107
@@ -29,7 +29,6 @@
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
this.panelContainer = new System.Windows.Forms.Panel();
|
||||
this.panelContent = new System.Windows.Forms.Panel();
|
||||
this.btnAnalyze = new System.Windows.Forms.Button();
|
||||
@@ -38,10 +37,9 @@
|
||||
this.treeFeatures = new System.Windows.Forms.TreeView();
|
||||
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.analyzeMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.previewMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.fixMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.seperatorToolStripMenuItem = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.restoreMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.seperatorToolStripMenuItem = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.helpMarkedFeatureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.Apps = new System.Windows.Forms.TabPage();
|
||||
this.checkedListBoxApps = new System.Windows.Forms.CheckedListBox();
|
||||
@@ -50,15 +48,17 @@
|
||||
this.rtbLogger = new System.Windows.Forms.RichTextBox();
|
||||
this.btnFix = new System.Windows.Forms.Button();
|
||||
this.panelHeader = new System.Windows.Forms.Panel();
|
||||
this.btnGitHub = new System.Windows.Forms.Button();
|
||||
this.lblOSInfo = new System.Windows.Forms.Label();
|
||||
this.lblVersionInfo = new System.Windows.Forms.Label();
|
||||
this.lblHeader = new System.Windows.Forms.Label();
|
||||
this.pictureHeader = new System.Windows.Forms.PictureBox();
|
||||
this.btnRestore = new System.Windows.Forms.Button();
|
||||
this.linkUpdateCheck = new System.Windows.Forms.LinkLabel();
|
||||
this.btnSettings = new System.Windows.Forms.Button();
|
||||
this.btnHome = new System.Windows.Forms.Button();
|
||||
this.btnTools = new System.Windows.Forms.Button();
|
||||
this.btnFixer = new System.Windows.Forms.Button();
|
||||
this.linkSelection = new System.Windows.Forms.LinkLabel();
|
||||
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.panelContainer.SuspendLayout();
|
||||
this.panelContent.SuspendLayout();
|
||||
this.tabControl.SuspendLayout();
|
||||
@@ -77,15 +77,15 @@
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.panelContainer.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.panelContainer.Controls.Add(this.panelContent);
|
||||
this.panelContainer.Location = new System.Drawing.Point(99, 62);
|
||||
this.panelContainer.Location = new System.Drawing.Point(90, 69);
|
||||
this.panelContainer.Name = "panelContainer";
|
||||
this.panelContainer.Size = new System.Drawing.Size(611, 382);
|
||||
this.panelContainer.Size = new System.Drawing.Size(613, 375);
|
||||
this.panelContainer.TabIndex = 198;
|
||||
//
|
||||
// panelContent
|
||||
//
|
||||
this.panelContent.AutoScroll = true;
|
||||
this.panelContent.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||
this.panelContent.BackColor = System.Drawing.Color.White;
|
||||
this.panelContent.Controls.Add(this.btnAnalyze);
|
||||
this.panelContent.Controls.Add(this.tabControl);
|
||||
this.panelContent.Controls.Add(this.groupBox);
|
||||
@@ -93,7 +93,7 @@
|
||||
this.panelContent.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panelContent.Location = new System.Drawing.Point(0, 0);
|
||||
this.panelContent.Name = "panelContent";
|
||||
this.panelContent.Size = new System.Drawing.Size(611, 382);
|
||||
this.panelContent.Size = new System.Drawing.Size(613, 375);
|
||||
this.panelContent.TabIndex = 205;
|
||||
//
|
||||
// btnAnalyze
|
||||
@@ -102,7 +102,7 @@
|
||||
this.btnAnalyze.AutoEllipsis = true;
|
||||
this.btnAnalyze.FlatStyle = System.Windows.Forms.FlatStyle.System;
|
||||
this.btnAnalyze.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.btnAnalyze.Location = new System.Drawing.Point(280, 346);
|
||||
this.btnAnalyze.Location = new System.Drawing.Point(268, 339);
|
||||
this.btnAnalyze.Name = "btnAnalyze";
|
||||
this.btnAnalyze.Size = new System.Drawing.Size(121, 29);
|
||||
this.btnAnalyze.TabIndex = 1;
|
||||
@@ -116,45 +116,42 @@
|
||||
| System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.tabControl.Controls.Add(this.Windows);
|
||||
this.tabControl.Controls.Add(this.Apps);
|
||||
this.tabControl.HotTrack = true;
|
||||
this.tabControl.Location = new System.Drawing.Point(0, 0);
|
||||
this.tabControl.ItemSize = new System.Drawing.Size(68, 21);
|
||||
this.tabControl.Location = new System.Drawing.Point(7, 5);
|
||||
this.tabControl.Name = "tabControl";
|
||||
this.tabControl.Padding = new System.Drawing.Point(20, 8);
|
||||
this.tabControl.SelectedIndex = 0;
|
||||
this.tabControl.ShowToolTips = true;
|
||||
this.tabControl.Size = new System.Drawing.Size(270, 376);
|
||||
this.tabControl.SizeMode = System.Windows.Forms.TabSizeMode.Fixed;
|
||||
this.tabControl.Size = new System.Drawing.Size(255, 363);
|
||||
this.tabControl.SizeMode = System.Windows.Forms.TabSizeMode.FillToRight;
|
||||
this.tabControl.TabIndex = 199;
|
||||
//
|
||||
// Windows
|
||||
//
|
||||
this.Windows.AutoScroll = true;
|
||||
this.Windows.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
|
||||
this.Windows.Controls.Add(this.treeFeatures);
|
||||
this.Windows.Location = new System.Drawing.Point(4, 32);
|
||||
this.Windows.Location = new System.Drawing.Point(4, 25);
|
||||
this.Windows.Name = "Windows";
|
||||
this.Windows.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.Windows.Size = new System.Drawing.Size(262, 340);
|
||||
this.Windows.Size = new System.Drawing.Size(247, 334);
|
||||
this.Windows.TabIndex = 0;
|
||||
this.Windows.Text = "Windows";
|
||||
//
|
||||
// treeFeatures
|
||||
//
|
||||
this.treeFeatures.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(242)))), ((int)(((byte)(242)))), ((int)(((byte)(242)))));
|
||||
this.treeFeatures.BackColor = System.Drawing.Color.White;
|
||||
this.treeFeatures.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.treeFeatures.CheckBoxes = true;
|
||||
this.treeFeatures.ContextMenuStrip = this.contextMenuStrip;
|
||||
this.treeFeatures.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.treeFeatures.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.treeFeatures.Indent = 20;
|
||||
this.treeFeatures.ItemHeight = 23;
|
||||
this.treeFeatures.Location = new System.Drawing.Point(3, 3);
|
||||
this.treeFeatures.Location = new System.Drawing.Point(0, 0);
|
||||
this.treeFeatures.Name = "treeFeatures";
|
||||
this.treeFeatures.ShowLines = false;
|
||||
this.treeFeatures.ShowNodeToolTips = true;
|
||||
this.treeFeatures.ShowPlusMinus = false;
|
||||
this.treeFeatures.ShowRootLines = false;
|
||||
this.treeFeatures.Size = new System.Drawing.Size(256, 334);
|
||||
this.treeFeatures.TabIndex = 196;
|
||||
this.treeFeatures.Size = new System.Drawing.Size(247, 334);
|
||||
this.treeFeatures.TabIndex = 0;
|
||||
this.treeFeatures.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.treeFeatures_AfterCheck);
|
||||
this.treeFeatures.MouseDown += new System.Windows.Forms.MouseEventHandler(this.treeFeatures_MouseDown);
|
||||
//
|
||||
@@ -162,14 +159,13 @@
|
||||
//
|
||||
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.analyzeMarkedFeatureToolStripMenuItem,
|
||||
this.previewMarkedFeatureToolStripMenuItem,
|
||||
this.fixMarkedFeatureToolStripMenuItem,
|
||||
this.seperatorToolStripMenuItem,
|
||||
this.restoreMarkedFeatureToolStripMenuItem,
|
||||
this.seperatorToolStripMenuItem,
|
||||
this.helpMarkedFeatureToolStripMenuItem});
|
||||
this.contextMenuStrip.Name = "contextManualMenu";
|
||||
this.contextMenuStrip.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
|
||||
this.contextMenuStrip.Size = new System.Drawing.Size(119, 120);
|
||||
this.contextMenuStrip.Size = new System.Drawing.Size(119, 98);
|
||||
//
|
||||
// analyzeMarkedFeatureToolStripMenuItem
|
||||
//
|
||||
@@ -178,13 +174,6 @@
|
||||
this.analyzeMarkedFeatureToolStripMenuItem.Text = "Analyze";
|
||||
this.analyzeMarkedFeatureToolStripMenuItem.Click += new System.EventHandler(this.analyzeMarkedFeatureToolStripMenuItem_Click);
|
||||
//
|
||||
// previewMarkedFeatureToolStripMenuItem
|
||||
//
|
||||
this.previewMarkedFeatureToolStripMenuItem.Name = "previewMarkedFeatureToolStripMenuItem";
|
||||
this.previewMarkedFeatureToolStripMenuItem.Size = new System.Drawing.Size(118, 22);
|
||||
this.previewMarkedFeatureToolStripMenuItem.Text = "Preview";
|
||||
this.previewMarkedFeatureToolStripMenuItem.Click += new System.EventHandler(this.previewMarkedFeatureToolStripMenuItem_Click);
|
||||
//
|
||||
// fixMarkedFeatureToolStripMenuItem
|
||||
//
|
||||
this.fixMarkedFeatureToolStripMenuItem.Name = "fixMarkedFeatureToolStripMenuItem";
|
||||
@@ -192,11 +181,6 @@
|
||||
this.fixMarkedFeatureToolStripMenuItem.Text = "Fix";
|
||||
this.fixMarkedFeatureToolStripMenuItem.Click += new System.EventHandler(this.fixMarkedFeatureToolStripMenuItem_Click);
|
||||
//
|
||||
// seperatorToolStripMenuItem
|
||||
//
|
||||
this.seperatorToolStripMenuItem.Name = "seperatorToolStripMenuItem";
|
||||
this.seperatorToolStripMenuItem.Size = new System.Drawing.Size(115, 6);
|
||||
//
|
||||
// restoreMarkedFeatureToolStripMenuItem
|
||||
//
|
||||
this.restoreMarkedFeatureToolStripMenuItem.Name = "restoreMarkedFeatureToolStripMenuItem";
|
||||
@@ -204,6 +188,11 @@
|
||||
this.restoreMarkedFeatureToolStripMenuItem.Text = "Restore";
|
||||
this.restoreMarkedFeatureToolStripMenuItem.Click += new System.EventHandler(this.restoreMarkedFeatureToolStripMenuItem_Click);
|
||||
//
|
||||
// seperatorToolStripMenuItem
|
||||
//
|
||||
this.seperatorToolStripMenuItem.Name = "seperatorToolStripMenuItem";
|
||||
this.seperatorToolStripMenuItem.Size = new System.Drawing.Size(115, 6);
|
||||
//
|
||||
// helpMarkedFeatureToolStripMenuItem
|
||||
//
|
||||
this.helpMarkedFeatureToolStripMenuItem.Name = "helpMarkedFeatureToolStripMenuItem";
|
||||
@@ -214,30 +203,28 @@
|
||||
//
|
||||
// Apps
|
||||
//
|
||||
this.Apps.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(242)))), ((int)(((byte)(242)))), ((int)(((byte)(242)))));
|
||||
this.Apps.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
|
||||
this.Apps.Controls.Add(this.checkedListBoxApps);
|
||||
this.Apps.Location = new System.Drawing.Point(4, 32);
|
||||
this.Apps.Location = new System.Drawing.Point(4, 25);
|
||||
this.Apps.Name = "Apps";
|
||||
this.Apps.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.Apps.Size = new System.Drawing.Size(262, 340);
|
||||
this.Apps.Size = new System.Drawing.Size(247, 334);
|
||||
this.Apps.TabIndex = 1;
|
||||
this.Apps.Text = "Apps";
|
||||
this.Apps.Text = "Applications";
|
||||
//
|
||||
// checkedListBoxApps
|
||||
//
|
||||
this.checkedListBoxApps.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(242)))), ((int)(((byte)(242)))), ((int)(((byte)(242)))));
|
||||
this.checkedListBoxApps.BackColor = System.Drawing.Color.White;
|
||||
this.checkedListBoxApps.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.checkedListBoxApps.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.checkedListBoxApps.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.checkedListBoxApps.FormattingEnabled = true;
|
||||
this.checkedListBoxApps.Items.AddRange(new object[] {
|
||||
"No analysis yet"});
|
||||
this.checkedListBoxApps.Location = new System.Drawing.Point(3, 3);
|
||||
this.checkedListBoxApps.Location = new System.Drawing.Point(0, 0);
|
||||
this.checkedListBoxApps.Name = "checkedListBoxApps";
|
||||
this.checkedListBoxApps.Size = new System.Drawing.Size(256, 334);
|
||||
this.checkedListBoxApps.Size = new System.Drawing.Size(247, 334);
|
||||
this.checkedListBoxApps.Sorted = true;
|
||||
this.checkedListBoxApps.TabIndex = 336;
|
||||
this.checkedListBoxApps.ThreeDCheckBoxes = true;
|
||||
//
|
||||
// groupBox
|
||||
//
|
||||
@@ -247,9 +234,10 @@
|
||||
this.groupBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||
this.groupBox.Controls.Add(this.comboLogActions);
|
||||
this.groupBox.Controls.Add(this.rtbLogger);
|
||||
this.groupBox.Location = new System.Drawing.Point(280, 21);
|
||||
this.groupBox.ForeColor = System.Drawing.SystemColors.ControlDarkDark;
|
||||
this.groupBox.Location = new System.Drawing.Point(268, 21);
|
||||
this.groupBox.Name = "groupBox";
|
||||
this.groupBox.Size = new System.Drawing.Size(320, 317);
|
||||
this.groupBox.Size = new System.Drawing.Size(334, 310);
|
||||
this.groupBox.TabIndex = 200;
|
||||
this.groupBox.TabStop = false;
|
||||
//
|
||||
@@ -257,13 +245,14 @@
|
||||
//
|
||||
this.comboLogActions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.comboLogActions.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
|
||||
this.comboLogActions.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboLogActions.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.comboLogActions.Font = new System.Drawing.Font("Tahoma", 8.25F);
|
||||
this.comboLogActions.FormattingEnabled = true;
|
||||
this.comboLogActions.Location = new System.Drawing.Point(7, 292);
|
||||
this.comboLogActions.Location = new System.Drawing.Point(7, 285);
|
||||
this.comboLogActions.Name = "comboLogActions";
|
||||
this.comboLogActions.Size = new System.Drawing.Size(305, 21);
|
||||
this.comboLogActions.Size = new System.Drawing.Size(319, 21);
|
||||
this.comboLogActions.TabIndex = 210;
|
||||
this.comboLogActions.Visible = false;
|
||||
//
|
||||
@@ -274,13 +263,13 @@
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.rtbLogger.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||
this.rtbLogger.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.rtbLogger.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.rtbLogger.Location = new System.Drawing.Point(7, 12);
|
||||
this.rtbLogger.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.rtbLogger.Location = new System.Drawing.Point(7, 19);
|
||||
this.rtbLogger.Name = "rtbLogger";
|
||||
this.rtbLogger.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical;
|
||||
this.rtbLogger.Size = new System.Drawing.Size(305, 273);
|
||||
this.rtbLogger.Size = new System.Drawing.Size(319, 263);
|
||||
this.rtbLogger.TabIndex = 195;
|
||||
this.rtbLogger.Text = "";
|
||||
this.rtbLogger.WordWrap = false;
|
||||
//
|
||||
// btnFix
|
||||
//
|
||||
@@ -288,7 +277,7 @@
|
||||
this.btnFix.AutoEllipsis = true;
|
||||
this.btnFix.FlatStyle = System.Windows.Forms.FlatStyle.System;
|
||||
this.btnFix.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.btnFix.Location = new System.Drawing.Point(480, 346);
|
||||
this.btnFix.Location = new System.Drawing.Point(482, 339);
|
||||
this.btnFix.Name = "btnFix";
|
||||
this.btnFix.Size = new System.Drawing.Size(121, 29);
|
||||
this.btnFix.TabIndex = 2;
|
||||
@@ -299,6 +288,7 @@
|
||||
// panelHeader
|
||||
//
|
||||
this.panelHeader.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(77)))), ((int)(((byte)(77)))));
|
||||
this.panelHeader.Controls.Add(this.btnGitHub);
|
||||
this.panelHeader.Controls.Add(this.lblOSInfo);
|
||||
this.panelHeader.Controls.Add(this.lblVersionInfo);
|
||||
this.panelHeader.Controls.Add(this.lblHeader);
|
||||
@@ -310,21 +300,42 @@
|
||||
this.panelHeader.TabIndex = 204;
|
||||
this.panelHeader.Paint += new System.Windows.Forms.PaintEventHandler(this.panelHeader_Paint);
|
||||
//
|
||||
// btnGitHub
|
||||
//
|
||||
this.btnGitHub.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnGitHub.AutoSize = true;
|
||||
this.btnGitHub.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.btnGitHub.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(170)))), ((int)(((byte)(210)))));
|
||||
this.btnGitHub.FlatAppearance.BorderSize = 0;
|
||||
this.btnGitHub.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnGitHub.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnGitHub.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.btnGitHub.Location = new System.Drawing.Point(657, 7);
|
||||
this.btnGitHub.Name = "btnGitHub";
|
||||
this.btnGitHub.Size = new System.Drawing.Size(40, 40);
|
||||
this.btnGitHub.TabIndex = 201;
|
||||
this.btnGitHub.TabStop = false;
|
||||
this.toolTip.SetToolTip(this.btnGitHub, "Love CrapFixer? It’s open source — but your support keeps it alive! 💖");
|
||||
this.btnGitHub.UseVisualStyleBackColor = true;
|
||||
this.btnGitHub.Click += new System.EventHandler(this.btnGitHub_Click);
|
||||
//
|
||||
// lblOSInfo
|
||||
//
|
||||
this.lblOSInfo.AutoSize = true;
|
||||
this.lblOSInfo.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F);
|
||||
this.lblOSInfo.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblOSInfo.Font = new System.Drawing.Font("Tahoma", 7.6F);
|
||||
this.lblOSInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(230)))), ((int)(((byte)(230)))));
|
||||
this.lblOSInfo.Location = new System.Drawing.Point(90, 37);
|
||||
this.lblOSInfo.Name = "lblOSInfo";
|
||||
this.lblOSInfo.Size = new System.Drawing.Size(116, 13);
|
||||
this.lblOSInfo.Size = new System.Drawing.Size(120, 13);
|
||||
this.lblOSInfo.TabIndex = 200;
|
||||
this.lblOSInfo.Text = "Checking your system..";
|
||||
//
|
||||
// lblVersionInfo
|
||||
//
|
||||
this.lblVersionInfo.AutoSize = true;
|
||||
this.lblVersionInfo.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.5F);
|
||||
this.lblVersionInfo.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblVersionInfo.Font = new System.Drawing.Font("Tahoma", 7.6F);
|
||||
this.lblVersionInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(230)))), ((int)(((byte)(230)))));
|
||||
this.lblVersionInfo.Location = new System.Drawing.Point(198, 15);
|
||||
this.lblVersionInfo.Name = "lblVersionInfo";
|
||||
@@ -335,6 +346,8 @@
|
||||
// lblHeader
|
||||
//
|
||||
this.lblHeader.AutoEllipsis = true;
|
||||
this.lblHeader.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblHeader.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.lblHeader.Font = new System.Drawing.Font("Tahoma", 14F, System.Drawing.FontStyle.Bold);
|
||||
this.lblHeader.ForeColor = System.Drawing.Color.White;
|
||||
this.lblHeader.Location = new System.Drawing.Point(89, 9);
|
||||
@@ -342,29 +355,35 @@
|
||||
this.lblHeader.Size = new System.Drawing.Size(117, 25);
|
||||
this.lblHeader.TabIndex = 1;
|
||||
this.lblHeader.Text = "CrapFixer";
|
||||
this.toolTip.SetToolTip(this.lblHeader, "Click here to visit the CrapFixer website at github.com/builtbybel/crapfixer");
|
||||
this.lblHeader.UseCompatibleTextRendering = true;
|
||||
//
|
||||
// pictureHeader
|
||||
//
|
||||
this.pictureHeader.Image = ((System.Drawing.Image)(resources.GetObject("pictureHeader.Image")));
|
||||
this.pictureHeader.BackColor = System.Drawing.Color.Transparent;
|
||||
this.pictureHeader.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.pictureHeader.Image = global::CFixer.Properties.Resources.AppIcon;
|
||||
this.pictureHeader.InitialImage = null;
|
||||
this.pictureHeader.Location = new System.Drawing.Point(30, 9);
|
||||
this.pictureHeader.Name = "pictureHeader";
|
||||
this.pictureHeader.Size = new System.Drawing.Size(44, 41);
|
||||
this.pictureHeader.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.pictureHeader.TabIndex = 0;
|
||||
this.pictureHeader.TabStop = false;
|
||||
this.toolTip.SetToolTip(this.pictureHeader, "Click here to visit the CrapFixer website at github.com/builtbybel/crapfixer");
|
||||
//
|
||||
// btnRestore
|
||||
//
|
||||
this.btnRestore.AutoEllipsis = true;
|
||||
this.btnRestore.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.btnRestore.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(114)))), ((int)(((byte)(114)))), ((int)(((byte)(114)))));
|
||||
this.btnRestore.Cursor = System.Windows.Forms.Cursors.Default;
|
||||
this.btnRestore.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(170)))), ((int)(((byte)(210)))));
|
||||
this.btnRestore.FlatAppearance.BorderSize = 0;
|
||||
this.btnRestore.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnRestore.Font = new System.Drawing.Font("Tahoma", 8.25F);
|
||||
this.btnRestore.ForeColor = System.Drawing.Color.White;
|
||||
this.btnRestore.Location = new System.Drawing.Point(0, 129);
|
||||
this.btnRestore.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnRestore.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.btnRestore.Location = new System.Drawing.Point(10, 142);
|
||||
this.btnRestore.Name = "btnRestore";
|
||||
this.btnRestore.Size = new System.Drawing.Size(99, 69);
|
||||
this.btnRestore.Size = new System.Drawing.Size(80, 60);
|
||||
this.btnRestore.TabIndex = 198;
|
||||
this.btnRestore.TabStop = false;
|
||||
this.btnRestore.Text = "&Restore";
|
||||
@@ -379,46 +398,48 @@
|
||||
this.linkUpdateCheck.AutoSize = true;
|
||||
this.linkUpdateCheck.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.linkUpdateCheck.LinkColor = System.Drawing.Color.White;
|
||||
this.linkUpdateCheck.Location = new System.Drawing.Point(595, 447);
|
||||
this.linkUpdateCheck.Location = new System.Drawing.Point(590, 447);
|
||||
this.linkUpdateCheck.Name = "linkUpdateCheck";
|
||||
this.linkUpdateCheck.Size = new System.Drawing.Size(95, 13);
|
||||
this.linkUpdateCheck.Size = new System.Drawing.Size(107, 13);
|
||||
this.linkUpdateCheck.TabIndex = 203;
|
||||
this.linkUpdateCheck.TabStop = true;
|
||||
this.linkUpdateCheck.Text = "Check for updates";
|
||||
this.linkUpdateCheck.TextAlign = System.Drawing.ContentAlignment.TopCenter;
|
||||
this.linkUpdateCheck.Text = "Check for updates...";
|
||||
this.linkUpdateCheck.TextAlign = System.Drawing.ContentAlignment.TopCenter;
|
||||
this.linkUpdateCheck.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkUpdateCheck_LinkClicked);
|
||||
//
|
||||
// btnSettings
|
||||
// btnTools
|
||||
//
|
||||
this.btnSettings.AutoEllipsis = true;
|
||||
this.btnSettings.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.btnSettings.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(114)))), ((int)(((byte)(114)))), ((int)(((byte)(114)))));
|
||||
this.btnSettings.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnSettings.Font = new System.Drawing.Font("Tahoma", 8.25F);
|
||||
this.btnSettings.ForeColor = System.Drawing.Color.White;
|
||||
this.btnSettings.Location = new System.Drawing.Point(0, 197);
|
||||
this.btnSettings.Name = "btnSettings";
|
||||
this.btnSettings.Size = new System.Drawing.Size(99, 69);
|
||||
this.btnSettings.TabIndex = 205;
|
||||
this.btnSettings.TabStop = false;
|
||||
this.btnSettings.Text = "&Options";
|
||||
this.btnSettings.UseVisualStyleBackColor = true;
|
||||
this.btnTools.AutoEllipsis = true;
|
||||
this.btnTools.Cursor = System.Windows.Forms.Cursors.Default;
|
||||
this.btnTools.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(170)))), ((int)(((byte)(210)))));
|
||||
this.btnTools.FlatAppearance.BorderSize = 0;
|
||||
this.btnTools.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnTools.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnTools.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.btnTools.Location = new System.Drawing.Point(10, 210);
|
||||
this.btnTools.Name = "btnTools";
|
||||
this.btnTools.Size = new System.Drawing.Size(80, 60);
|
||||
this.btnTools.TabIndex = 205;
|
||||
this.btnTools.TabStop = false;
|
||||
this.btnTools.Text = "&Tools";
|
||||
this.btnTools.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnHome
|
||||
// btnFixer
|
||||
//
|
||||
this.btnHome.AutoEllipsis = true;
|
||||
this.btnHome.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(145)))), ((int)(((byte)(235)))));
|
||||
this.btnHome.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.btnHome.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(66)))), ((int)(((byte)(131)))), ((int)(((byte)(222)))));
|
||||
this.btnHome.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnHome.Font = new System.Drawing.Font("Tahoma", 8.25F);
|
||||
this.btnHome.ForeColor = System.Drawing.Color.White;
|
||||
this.btnHome.Location = new System.Drawing.Point(0, 61);
|
||||
this.btnHome.Name = "btnHome";
|
||||
this.btnHome.Size = new System.Drawing.Size(99, 69);
|
||||
this.btnHome.TabIndex = 206;
|
||||
this.btnHome.TabStop = false;
|
||||
this.btnHome.Text = "&Fixer";
|
||||
this.btnHome.UseVisualStyleBackColor = false;
|
||||
this.btnFixer.AutoEllipsis = true;
|
||||
this.btnFixer.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(150)))), ((int)(((byte)(200)))), ((int)(((byte)(240)))));
|
||||
this.btnFixer.Cursor = System.Windows.Forms.Cursors.Default;
|
||||
this.btnFixer.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(170)))), ((int)(((byte)(210)))));
|
||||
this.btnFixer.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnFixer.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnFixer.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.btnFixer.Location = new System.Drawing.Point(10, 74);
|
||||
this.btnFixer.Name = "btnFixer";
|
||||
this.btnFixer.Size = new System.Drawing.Size(80, 60);
|
||||
this.btnFixer.TabIndex = 206;
|
||||
this.btnFixer.TabStop = false;
|
||||
this.btnFixer.Text = "&Fixer";
|
||||
this.btnFixer.UseVisualStyleBackColor = false;
|
||||
//
|
||||
// linkSelection
|
||||
//
|
||||
@@ -441,15 +462,17 @@
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(104)))), ((int)(((byte)(104)))), ((int)(((byte)(104)))));
|
||||
this.AutoScroll = true;
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(103)))), ((int)(((byte)(103)))), ((int)(((byte)(103)))));
|
||||
this.ClientSize = new System.Drawing.Size(710, 466);
|
||||
this.Controls.Add(this.linkSelection);
|
||||
this.Controls.Add(this.btnHome);
|
||||
this.Controls.Add(this.btnSettings);
|
||||
this.Controls.Add(this.btnFixer);
|
||||
this.Controls.Add(this.btnTools);
|
||||
this.Controls.Add(this.panelHeader);
|
||||
this.Controls.Add(this.btnRestore);
|
||||
this.Controls.Add(this.linkUpdateCheck);
|
||||
this.Controls.Add(this.panelContainer);
|
||||
this.MinimumSize = new System.Drawing.Size(642, 337);
|
||||
this.Name = "MainForm";
|
||||
this.ShowIcon = false;
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
|
||||
@@ -495,13 +518,14 @@
|
||||
private System.Windows.Forms.Panel panelContent;
|
||||
private System.Windows.Forms.LinkLabel linkUpdateCheck;
|
||||
private System.Windows.Forms.ToolStripMenuItem helpMarkedFeatureToolStripMenuItem;
|
||||
private System.Windows.Forms.TreeView treeFeatures;
|
||||
private System.Windows.Forms.Label lblOSInfo;
|
||||
private System.Windows.Forms.Button btnSettings;
|
||||
private System.Windows.Forms.Button btnHome;
|
||||
private System.Windows.Forms.Button btnTools;
|
||||
private System.Windows.Forms.Button btnFixer;
|
||||
private System.Windows.Forms.LinkLabel linkSelection;
|
||||
private System.Windows.Forms.ToolStripMenuItem previewMarkedFeatureToolStripMenuItem;
|
||||
private System.Windows.Forms.ComboBox comboLogActions;
|
||||
private System.Windows.Forms.TreeView treeFeatures;
|
||||
private System.Windows.Forms.Button btnGitHub;
|
||||
private System.Windows.Forms.ToolTip toolTip;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+124
-97
@@ -4,6 +4,7 @@ using CFixer.Views;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
@@ -21,6 +22,7 @@ namespace CrapFixer
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
IniStateManager.ApplyWindowState(this);
|
||||
|
||||
// Set up the main navigation manager and logger
|
||||
_navigationManager = new NavigationManager(panelContainer);
|
||||
@@ -28,66 +30,67 @@ namespace CrapFixer
|
||||
|
||||
// Set up log actions controller
|
||||
_logActions = new LogActions(rtbLogger);
|
||||
_logActionsController = new LogActionsController(comboLogActions, _logActions);
|
||||
}
|
||||
|
||||
// Load features and plugins, and restore INI state if enabled
|
||||
private async void MainForm_Shown(object sender, EventArgs e)
|
||||
{
|
||||
await InitializeUI(); // _ = InitializeUI();
|
||||
InitializeAppState();
|
||||
}
|
||||
|
||||
private void InitializeAppState()
|
||||
{
|
||||
// Load features and plugins into the tree view
|
||||
FeatureNodeManager.LoadFeatures(treeFeatures);
|
||||
PluginManager.LoadPlugins(treeFeatures);
|
||||
if (IniStateManager.IsViewSettingEnabled("SETTINGS", "checkSaveToINI"))
|
||||
{
|
||||
IniStateManager.Load(treeFeatures, this);
|
||||
}
|
||||
|
||||
// Load settings from INI file if enabled
|
||||
IniStateManager.LoadFeaturesIfEnabled(treeFeatures);
|
||||
}
|
||||
|
||||
private void MainForm_Shown(object sender, EventArgs e)
|
||||
private async Task InitializeUI()
|
||||
{
|
||||
InitializeUI();
|
||||
}
|
||||
// Initialize the navigation handler with buttons
|
||||
_navigationHandler = new NavigationHandler(btnFixer, btnRestore, btnTools, btnGitHub);
|
||||
|
||||
private void InitializeUI()
|
||||
{
|
||||
// Set the default active button
|
||||
_navigationHandler = new NavigationHandler(btnHome, btnSettings);
|
||||
_navigationHandler.NavigationButtonClicked += button =>
|
||||
{
|
||||
if (button == btnHome)
|
||||
{
|
||||
_navigationManager.GoToMain();
|
||||
}
|
||||
else if (button == btnSettings)
|
||||
{
|
||||
_navigationManager.SwitchView(new OptionsView());
|
||||
}
|
||||
};
|
||||
// Load navigation icons
|
||||
await _navigationHandler.LoadNavigationIcons();
|
||||
|
||||
// Set up link label for update check
|
||||
linkUpdateCheck.LinkClicked += (_, __) =>
|
||||
Process.Start($"https://builtbybel.github.io/CrapFixer/update-check.html?version={Program.GetAppVersion()}");
|
||||
// Register navigation handler
|
||||
_navigationHandler.NavigationButtonClicked += NavigationHandler_NavigationButtonClicked;
|
||||
|
||||
// Set up log actions controller
|
||||
// Register click handlers for GitHub links
|
||||
pictureHeader.Click += PictureHeader_Click;
|
||||
lblHeader.Click += PictureHeader_Click;
|
||||
|
||||
// Re-initialize log actions controller (optional if not changed)
|
||||
_logActionsController = new LogActionsController(comboLogActions, _logActions);
|
||||
|
||||
// Set up version labels
|
||||
async Task SetVersionLabels()
|
||||
// Set version and OS info
|
||||
lblVersionInfo.Text = $"v{Program.GetAppVersion()} ";
|
||||
lblOSInfo.Text = await OSHelper.OSHelper.GetWindowsVersion();
|
||||
}
|
||||
|
||||
// Handles navigation button clicks and switches views accordingly
|
||||
private void NavigationHandler_NavigationButtonClicked(Button button)
|
||||
{
|
||||
if (button == btnFixer)
|
||||
{
|
||||
lblVersionInfo.Text = $"v{Program.GetAppVersion()} ";
|
||||
lblOSInfo.Text = await OSHelper.OSHelper.GetWindowsVersion();
|
||||
_navigationManager.GoToMain();
|
||||
}
|
||||
else if (button == btnTools)
|
||||
{
|
||||
_navigationManager.SwitchView(new OptionsView());
|
||||
}
|
||||
_ = SetVersionLabels();
|
||||
}
|
||||
|
||||
private async void btnAnalyze_Click(object sender, EventArgs e)
|
||||
{
|
||||
rtbLogger.Clear();
|
||||
|
||||
// Analyze features
|
||||
await FeatureNodeManager.AnalyzeAll(treeFeatures.Nodes);
|
||||
|
||||
// Analyze plugins
|
||||
foreach (TreeNode node in treeFeatures.Nodes)
|
||||
{
|
||||
PluginManager.AnalyzeAll(node);
|
||||
}
|
||||
await PluginManager.AnalyzeAllPlugins(treeFeatures.Nodes);
|
||||
|
||||
// Analyze apps
|
||||
await AnalyzeApps();
|
||||
@@ -99,40 +102,35 @@ namespace CrapFixer
|
||||
/// <summary>
|
||||
/// Analyzes the apps and logs the results.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task AnalyzeApps()
|
||||
{
|
||||
checkedListBoxApps.Items.Clear();
|
||||
|
||||
// Try loading external bloatware list from file
|
||||
string[] predefined = _appManager.LoadExternalBloatwareList();
|
||||
// Try loading patterns from CFEnhancer.txt (located in Plugins folder)
|
||||
var (bloatwarePatterns, whitelistPatterns, scanAll) = _appManager.LoadExternalBloatwarePatterns();
|
||||
|
||||
if (predefined.Length == 0)
|
||||
if (bloatwarePatterns.Length == 0 && !scanAll)
|
||||
{
|
||||
// Fallback to internal resource if external file not found or empty
|
||||
predefined = Resources.PredefinedApps?
|
||||
// Fallback to internal resource if external file not found or empty and scanAll is not enabled
|
||||
bloatwarePatterns = Resources.PredefinedApps?
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(s => s.Trim()).ToArray() ?? Array.Empty<string>();
|
||||
.Select(s => s.Trim().ToLower()).ToArray() ?? Array.Empty<string>();
|
||||
|
||||
// Logger.Log("Using built-in bloatware list.", LogLevel.Info);
|
||||
whitelistPatterns = Array.Empty<string>();
|
||||
Logger.Log("Using built-in bloatware list.", LogLevel.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log("Using external bloatware list via CFEnhancer", LogLevel.Info);
|
||||
Logger.Log("🔎 Plugin ready: CFEnhancer (external bloatware list)", LogLevel.Info);
|
||||
}
|
||||
|
||||
// Analyze installed apps against the predefined list
|
||||
var apps = await _appManager.AnalyzeAndLogAppsAsync(predefined);
|
||||
// Analyze installed apps based on patterns and whitelist, and optionally scan all
|
||||
var apps = await _appManager.AnalyzeAndLogAppsAsync(bloatwarePatterns, whitelistPatterns, scanAll);
|
||||
|
||||
foreach (var app in apps)
|
||||
{
|
||||
checkedListBoxApps.Items.Add(app.FullName);
|
||||
}
|
||||
|
||||
if (!apps.Any())
|
||||
{
|
||||
Logger.Log("✅ No bloatware apps found.", LogLevel.Info);
|
||||
}
|
||||
}
|
||||
|
||||
private async void btnFix_Click(object sender, EventArgs e)
|
||||
@@ -182,53 +180,64 @@ namespace CrapFixer
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes all plugins and features starting from the selected node from the context menu.
|
||||
/// </summary>
|
||||
private async void analyzeMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (treeFeatures.SelectedNode is TreeNode selectedNode)
|
||||
{
|
||||
if (PluginManager.IsPluginNode(selectedNode))
|
||||
Logger.Log($"🔎 Analyzing Feature: {selectedNode.Text}", LogLevel.Info);
|
||||
|
||||
// If a single node is selected (leaf node with no children),
|
||||
// always analyze this node regardless of its Checked state.
|
||||
if (selectedNode.Nodes.Count == 0)
|
||||
{
|
||||
await PluginManager.AnalyzePlugin(selectedNode);
|
||||
}
|
||||
else
|
||||
Logger.Log($"🔎 Analyzing Feature: {selectedNode.Text}", LogLevel.Info);
|
||||
{
|
||||
// If a parent node is selected (has children),
|
||||
// recursively analyze only the checked plugin nodes.
|
||||
await PluginManager.AnalyzeAll(selectedNode);
|
||||
}
|
||||
|
||||
// Perform feature-specific analysis (non-plugin)
|
||||
FeatureNodeManager.AnalyzeFeature(selectedNode);
|
||||
}
|
||||
}
|
||||
|
||||
private async void previewMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (treeFeatures.SelectedNode is TreeNode selectedNode)
|
||||
{
|
||||
if (PluginManager.IsPluginNode(selectedNode))
|
||||
{
|
||||
await PluginManager.AnalyzePlugin(selectedNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
FeatureNodeManager.PreviewChanges(selectedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fixes all checked plugin and feature nodes starting from the selected node from the context menu.
|
||||
/// </summary>
|
||||
private async void fixMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (treeFeatures.SelectedNode is TreeNode selectedNode)
|
||||
{
|
||||
if (PluginManager.IsPluginNode(selectedNode))
|
||||
await PluginManager.FixPlugin(selectedNode);
|
||||
else
|
||||
Logger.Log($"🔧 Fixing Feature: {selectedNode.Text}", LogLevel.Info);
|
||||
Logger.Log($"🔧 Fixing Feature: {selectedNode.Text}", LogLevel.Info);
|
||||
|
||||
// Recursively fix all checked feature nodes (non-plugin)
|
||||
await FeatureNodeManager.FixFeature(selectedNode);
|
||||
|
||||
// Recursively fix all checked plugin nodes starting from the selected node
|
||||
await PluginManager.FixPlugin(selectedNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
/// <summary>
|
||||
/// Restores the selected plugin or feature to its previous state from the context menu.
|
||||
/// </summary>
|
||||
private async void restoreMarkedFeatureToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (treeFeatures.SelectedNode is TreeNode selectedNode)
|
||||
{
|
||||
if (PluginManager.IsPluginNode(selectedNode))
|
||||
PluginManager.RestorePlugin(selectedNode);
|
||||
// Restore the plugin using its Undo command if available!
|
||||
await PluginManager.RestorePlugin(selectedNode);
|
||||
else
|
||||
Logger.Log($"↩️ Restoring Feature: {selectedNode.Text}", LogLevel.Info);
|
||||
|
||||
// Perform feature-specific restore (non-plugin)
|
||||
FeatureNodeManager.RestoreFeature(selectedNode);
|
||||
}
|
||||
}
|
||||
@@ -238,18 +247,6 @@ namespace CrapFixer
|
||||
if (treeFeatures.SelectedNode is TreeNode selectedNode)
|
||||
{
|
||||
FeatureNodeManager.ShowHelp(selectedNode);
|
||||
|
||||
// Prompt for online search
|
||||
var result = MessageBox.Show(
|
||||
"Would you like to search online for more information about this feature?",
|
||||
"Online Help",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
FeatureNodeManager.ShowHelpOnline(selectedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,26 +319,56 @@ namespace CrapFixer
|
||||
|
||||
private void panelHeader_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
Panel panel = sender as Panel;
|
||||
Graphics g = e.Graphics;
|
||||
var panel = sender as Panel;
|
||||
var g = e.Graphics;
|
||||
|
||||
// Fill background
|
||||
// Solid background: #4D4D4D
|
||||
g.Clear(Color.FromArgb(77, 77, 77));
|
||||
|
||||
// Draw a single magenta line at the bottom
|
||||
using (Pen pen = new Pen(Color.FromArgb(100, 255, 0, 255))) // Magenta with transparency
|
||||
// Inset line effect (3D-like): light line + shadow line
|
||||
Color baseColor = Color.FromArgb(80, 80, 80); // inset base
|
||||
|
||||
using (var topLine = new Pen(ControlPaint.Light(baseColor, 0.0f)))
|
||||
using (var bottomLine = new Pen(ControlPaint.Dark(baseColor, 0.2f)))
|
||||
{
|
||||
int y = panel.Height - 1; // Bottom-most pixel
|
||||
g.DrawLine(pen, 0, y, panel.Width, y);
|
||||
g.SmoothingMode = SmoothingMode.None;
|
||||
g.DrawLine(topLine, 0, panel.Height - 2, panel.Width, panel.Height - 2);
|
||||
g.DrawLine(bottomLine, 0, panel.Height - 1, panel.Width, panel.Height - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Handles click on the header image to open the GitHub page
|
||||
private void PictureHeader_Click(object sender, EventArgs e)
|
||||
{
|
||||
Utils.OpenGitHubPage(sender, e);
|
||||
}
|
||||
|
||||
// Handles link click to check for updates
|
||||
private void linkUpdateCheck_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
var updateUrl = $"https://builtbybel.github.io/CrapFixer/update-check.html?version={Program.GetAppVersion()}";
|
||||
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = updateUrl,
|
||||
UseShellExecute = true
|
||||
};
|
||||
Process.Start(psi);
|
||||
}
|
||||
|
||||
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (IniStateManager.IsViewSettingEnabled("SETTINGS", "checkSaveToINI"))
|
||||
{
|
||||
IniStateManager.Save(treeFeatures, this);
|
||||
}
|
||||
|
||||
Logger.OutputBox = null; // Remove reference
|
||||
}
|
||||
|
||||
private void btnGitHub_Click(object sender, EventArgs e)
|
||||
{
|
||||
_navigationManager.SwitchView(new OptionsView());
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-335
@@ -120,339 +120,10 @@
|
||||
<metadata name="contextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>23, 15</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="pictureHeader.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
AABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>171, 15</value>
|
||||
</metadata>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>171, 15</value>
|
||||
</metadata>
|
||||
</root>
|
||||
+104
-15
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CFixer
|
||||
@@ -13,14 +15,14 @@ namespace CFixer
|
||||
// List of all buttons managed by the navigation handler
|
||||
private readonly List<Button> _buttons;
|
||||
|
||||
// Color used for the active (selected) button
|
||||
private readonly Color _activeColor = Color.FromArgb(76, 145, 235);
|
||||
// Color used for the background of the active button
|
||||
private readonly Color _activeBackgroundColor = Color.FromArgb(180, 150, 200, 240);
|
||||
|
||||
// Color used for inactive (non-selected) buttons
|
||||
private readonly Color _inactiveColor = Color.FromArgb(104, 104, 104);
|
||||
// Color used for the background of inactive buttons (same as form)
|
||||
private readonly Color _inactiveBackgroundColor = Color.FromArgb(103, 103, 103);
|
||||
|
||||
// Border color for inactive buttons
|
||||
private readonly Color _inactiveBorderColor = Color.FromArgb(114, 114, 114);
|
||||
// Color used for the border of the active button
|
||||
private readonly Color _activeBorderColor = Color.FromArgb(255, 120, 170, 210);
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when a navigation button is clicked.
|
||||
@@ -46,28 +48,115 @@ namespace CFixer
|
||||
if (sender is Button clickedButton)
|
||||
{
|
||||
SetActive(clickedButton);
|
||||
clickedButton.FindForm().ActiveControl = null; // Remove focus so no extra border is drawn
|
||||
NavigationButtonClicked?.Invoke(clickedButton);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the specified button as active, changing colors accordingly.
|
||||
/// Sets the given button as active and updates the appearance of all buttons.
|
||||
/// </summary>
|
||||
/// <param name="activeButton">The button to highlight as active.</param>
|
||||
/// <param name="activeButton">The button to mark as active.</param>
|
||||
public void SetActive(Button activeButton)
|
||||
{
|
||||
foreach (var button in _buttons)
|
||||
{
|
||||
// Skip GitHub button to avoid conflicts with its custom behavior
|
||||
if (button.Name.Equals("btnGitHub", StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
bool isActive = button == activeButton;
|
||||
|
||||
// Set the background color for the button (active or inactive)
|
||||
button.BackColor = isActive ? _activeColor : _inactiveColor;
|
||||
if (isActive)
|
||||
{
|
||||
button.BackColor = _activeBackgroundColor;
|
||||
button.FlatAppearance.BorderColor = _activeBorderColor;
|
||||
button.FlatAppearance.BorderSize = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
button.BackColor = _inactiveBackgroundColor;
|
||||
button.FlatAppearance.BorderSize = 0;
|
||||
}
|
||||
|
||||
// Set the border color for the button (active or inactive)
|
||||
button.FlatAppearance.BorderColor = isActive ? _activeColor : _inactiveBorderColor;
|
||||
button.ForeColor = Color.WhiteSmoke;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the text color to white for both active and inactive
|
||||
button.ForeColor = Color.White;
|
||||
/// <summary>
|
||||
/// Loads and assigns icons to buttons asynchronously based on their names.
|
||||
/// </summary>
|
||||
/// <param name="iconFolder">The relative folder path where the icon files are located. Defaults to "icons". Each button's icon file name is
|
||||
/// derived from the button's name by removing the "btn" prefix, converting the remainder to lowercase, and
|
||||
/// appending ".png".</param>
|
||||
public async Task LoadNavigationIcons(string iconFolder = "icons")
|
||||
{
|
||||
string basePath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
string fullIconPath = Path.Combine(basePath, iconFolder);
|
||||
if (!Directory.Exists(fullIconPath)) return;
|
||||
|
||||
// Create graphics context to get system DPI scaling (default is 96 DPI)
|
||||
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
|
||||
{
|
||||
float dpiScale = g.DpiX / 96f;
|
||||
int defaultIconSize = (int)(32 * dpiScale); // Scale 32px base size with DPI
|
||||
int githubIconSize = (int)(42 * dpiScale); // Special size for GitHub button
|
||||
|
||||
foreach (var button in _buttons)
|
||||
{
|
||||
// Convert button name like "btnHome" > "home.png"
|
||||
string buttonName = button.Name.ToLower();
|
||||
string fileName;
|
||||
|
||||
if (buttonName == "btngithub")
|
||||
fileName = "github.png";
|
||||
else if (buttonName.StartsWith("btn"))
|
||||
fileName = buttonName.Replace("btn", "") + ".png";
|
||||
else
|
||||
continue;
|
||||
|
||||
string filePath = Path.Combine(fullIconPath, fileName);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
// Read file bytes asynchronously off the UI thread
|
||||
byte[] imageData = await Task.Run(() => File.ReadAllBytes(filePath));
|
||||
|
||||
using (var ms = new MemoryStream(imageData))
|
||||
using (Image original = Image.FromStream(ms))
|
||||
{
|
||||
int iconSize = buttonName == "btngithub" ? githubIconSize : defaultIconSize;
|
||||
|
||||
Bitmap resized = new Bitmap(iconSize, iconSize);
|
||||
try
|
||||
{
|
||||
using (Graphics gr = Graphics.FromImage(resized))
|
||||
{
|
||||
gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
|
||||
gr.DrawImage(original, 0, 0, iconSize, iconSize);
|
||||
}
|
||||
|
||||
// Set button image
|
||||
button.Image = resized;
|
||||
button.ImageAlign = ContentAlignment.TopCenter;
|
||||
button.TextAlign = ContentAlignment.BottomCenter;
|
||||
}
|
||||
catch
|
||||
{
|
||||
resized.Dispose(); // Cleanup if drawing fails
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Optional: log or ignore loading errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+273
-74
@@ -1,13 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Provides functionality to load, execute, analyze, and fix external PowerShell-based plugins.
|
||||
/// </summary>
|
||||
///
|
||||
public static class PluginManager
|
||||
{
|
||||
/// 1. Execute a PowerShell script asynchronously and log output/errors.
|
||||
public static async Task ExecutePlugin(string pluginPath)
|
||||
{
|
||||
try
|
||||
@@ -21,9 +28,6 @@ public static class PluginManager
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
|
||||
var outputBuilder = new StringBuilder();
|
||||
var errorBuilder = new StringBuilder();
|
||||
|
||||
process.OutputDataReceived += (s, e) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
@@ -50,6 +54,7 @@ public static class PluginManager
|
||||
}
|
||||
}
|
||||
|
||||
/// 2. Load all .ps1 plugin files from the 'plugins' folder into a TreeView.
|
||||
public static void LoadPlugins(TreeView treeView)
|
||||
{
|
||||
string pluginsFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
|
||||
@@ -57,13 +62,11 @@ public static class PluginManager
|
||||
if (!Directory.Exists(pluginsFolder))
|
||||
{
|
||||
Directory.CreateDirectory(pluginsFolder);
|
||||
// Logger.Log("No Plugins found.\nGet it on https://github.com/builtbybel/CrapFixer");
|
||||
return;
|
||||
}
|
||||
|
||||
var pluginsNode = new TreeNode("Plugins")
|
||||
{
|
||||
// NodeFont = new Font(treeView.Font, FontStyle.Bold),
|
||||
BackColor = Color.Magenta,
|
||||
ForeColor = Color.White
|
||||
};
|
||||
@@ -73,7 +76,7 @@ public static class PluginManager
|
||||
var scriptName = Path.GetFileNameWithoutExtension(scriptPath);
|
||||
var scriptNode = new TreeNode
|
||||
{
|
||||
Text = $"{scriptName} [PS]",
|
||||
Text = $"{scriptName}", // [PS]
|
||||
ToolTipText = scriptPath,
|
||||
Tag = scriptPath,
|
||||
Checked = false
|
||||
@@ -82,117 +85,313 @@ public static class PluginManager
|
||||
}
|
||||
|
||||
treeView.Nodes.Add(pluginsNode);
|
||||
treeView.ExpandAll(); // expand all nodes
|
||||
treeView.ExpandAll();
|
||||
}
|
||||
|
||||
public static void AnalyzeAll(TreeNode node)
|
||||
/// 3. Parse the [Commands] section from plugin content.
|
||||
private static Dictionary<string, string> ParseCommands(string pluginContent)
|
||||
{
|
||||
if (node.Tag is string path && node.Checked)
|
||||
{
|
||||
Logger.Log($"🔎 Plugin ready: {Path.GetFileName(path)}");
|
||||
}
|
||||
|
||||
foreach (TreeNode child in node.Nodes)
|
||||
AnalyzeAll(child);
|
||||
return ParseSection(pluginContent, "Commands");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes all checked plugins in the tree view.
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task FixChecked(TreeNode node)
|
||||
/// 4. Parse the [Expect] section from plugin content.
|
||||
private static Dictionary<string, string> ParseExpect(string pluginContent)
|
||||
{
|
||||
if (node.Checked)
|
||||
return ParseSection(pluginContent, "Expect");
|
||||
}
|
||||
|
||||
/// 5. Generic parser for named sections like [Commands] or [Expect].
|
||||
/// Lines must be in 'key = value' format.
|
||||
private static Dictionary<string, string> ParseSection(string content, string sectionName)
|
||||
{
|
||||
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
var lines = content.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
bool insideSection = false;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
// Show a warning for each checked plugin
|
||||
if (node.Tag is string pluginPath)
|
||||
var trimmed = line.Trim();
|
||||
if (trimmed.Equals($"[{sectionName}]", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var pluginName = Path.GetFileName(pluginPath); // get the plugin name
|
||||
var proceed = ShowPluginWarning(pluginName); // the warning message box
|
||||
if (!proceed) return; // If user chooses not to proceed, exit the method
|
||||
insideSection = true;
|
||||
continue;
|
||||
}
|
||||
// Exit the section when another section begins
|
||||
if (insideSection)
|
||||
{
|
||||
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
|
||||
break;
|
||||
|
||||
// Parse lines of form: key = value
|
||||
var idx = trimmed.IndexOf('=');
|
||||
if (idx > 0)
|
||||
{
|
||||
var key = trimmed.Substring(0, idx).Trim();
|
||||
var val = trimmed.Substring(idx + 1).Trim();
|
||||
result[key] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.Tag is string path && node.Checked)
|
||||
{
|
||||
await ExecutePlugin(path);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Recursively process all child nodes
|
||||
foreach (TreeNode child in node.Nodes)
|
||||
await FixChecked(child);
|
||||
/// 6. Execute a shell command (CMD) and return exit code and output.
|
||||
private static async Task<(int exitCode, string output)> ExecuteCommand(string command)
|
||||
{
|
||||
var process = new Process();
|
||||
var outputBuilder = new StringBuilder();
|
||||
|
||||
process.StartInfo.FileName = "cmd.exe";
|
||||
process.StartInfo.Arguments = $"/c \"{command}\"";
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
process.StartInfo.RedirectStandardError = true;
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
|
||||
process.OutputDataReceived += (s, e) => { if (e.Data != null) outputBuilder.AppendLine(e.Data); };
|
||||
process.ErrorDataReceived += (s, e) => { if (e.Data != null) outputBuilder.AppendLine(e.Data); };
|
||||
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
await Task.Run(() => process.WaitForExit());
|
||||
|
||||
return (process.ExitCode, outputBuilder.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes individual plugin files.
|
||||
/// 7. Analyzes a single plugin node by running its 'Check' command
|
||||
/// and comparing the output against expected values defined in the [Expect] section.
|
||||
/// Logs a summary indicating success if all checks pass, or warnings if mismatches occur.
|
||||
/// Only the specified plugin node is analyzed, regardless of its checked state.
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="node">The TreeNode representing the plugin to analyze, with script path stored in Tag.</param>
|
||||
public static async Task AnalyzePlugin(TreeNode node)
|
||||
{
|
||||
if (node?.Tag is string path && File.Exists(path))
|
||||
if (node == null || node.Tag == null || !File.Exists(node.Tag.ToString()))
|
||||
{
|
||||
string content = File.ReadAllText(path);
|
||||
Logger.Log(new string('=', 50), LogLevel.Custom);
|
||||
Logger.Log($"📄 Script content:{node.Text}\n{content}", LogLevel.Info);
|
||||
|
||||
await Task.CompletedTask;
|
||||
// Logger.Log($"❌ Script file not found for plugin: {node?.Text}", LogLevel.Error);
|
||||
Logger.Log(new string('-', 50), LogLevel.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"❌ Script file not found for plugin: {node?.Text}", LogLevel.Error);
|
||||
string pluginName = node.Text;
|
||||
string path = node.Tag.ToString();
|
||||
string content = File.ReadAllText(path);
|
||||
|
||||
Dictionary<string, string> commands = ParseCommands(content);
|
||||
Dictionary<string, string> expected = ParseExpect(content);
|
||||
|
||||
if (!commands.ContainsKey("Check"))
|
||||
{
|
||||
Logger.Log($"🔎 Plugin ready: [PS] {Path.GetFileName(path)}");
|
||||
Logger.Log(new string('-', 50), LogLevel.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
string checkCmd = commands["Check"];
|
||||
var result = await ExecuteCommand(checkCmd);
|
||||
string output = result.Item2;
|
||||
|
||||
bool allMatched = true;
|
||||
StringBuilder mismatchDetails = new StringBuilder();
|
||||
|
||||
foreach (var entry in expected)
|
||||
{
|
||||
string key = entry.Key;
|
||||
string expectedVal = entry.Value;
|
||||
|
||||
var match = Regex.Match(output, $@"{Regex.Escape(key)}\s+REG_\w+\s+(\S+)", RegexOptions.IgnoreCase);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
string actual = match.Groups[1].Value;
|
||||
|
||||
if (!expectedVal.Equals(actual, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
allMatched = false;
|
||||
mismatchDetails.AppendLine($" ➤ {key}: expected '{expectedVal}', found '{actual}'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
allMatched = false;
|
||||
mismatchDetails.AppendLine(
|
||||
$" ➤ Warning: The registry key '{key}' could not be located in the output. " +
|
||||
"This usually means the key is missing and the tweak will have to add it. " +
|
||||
"[InternalCode: Could not be parsed from output]");
|
||||
}
|
||||
}
|
||||
|
||||
if (allMatched)
|
||||
{
|
||||
Logger.Log($"✅ Plugin: {pluginName} is properly configured.", LogLevel.Info);
|
||||
node.ForeColor = Color.Gray;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"❌ Plugin: {pluginName} requires attention.\n{mismatchDetails}", LogLevel.Warning);
|
||||
node.ForeColor = Color.Red;
|
||||
}
|
||||
|
||||
Logger.Log(new string('-', 50), LogLevel.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes individual plugin files.
|
||||
/// 8. Applies the fix to a single plugin node.
|
||||
/// This method processes only the specified node regardless of its checked state.
|
||||
/// It attempts to run the "Do" command from the plugin script, or falls back to executing the entire script.
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task FixPlugin(TreeNode node)
|
||||
{
|
||||
if (node?.Tag is string path && File.Exists(path))
|
||||
{
|
||||
Logger.Log($"🔧 Executing Plugin: {node.Text}", LogLevel.Info);
|
||||
await ExecutePlugin(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"❌ Script file not found for plugin: {node?.Text}", LogLevel.Error);
|
||||
}
|
||||
}
|
||||
var content = File.ReadAllText(path);
|
||||
var commands = ParseCommands(content);
|
||||
|
||||
public static void RestorePlugin(TreeNode node)
|
||||
{
|
||||
Logger.Log($"⚠️ Restore is not available for Plugins: {node?.Text}", LogLevel.Warning);
|
||||
MessageBox.Show("Restore is not possible for Plugins.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
if (commands.TryGetValue("Do", out string doCmd))
|
||||
{
|
||||
Logger.Log($"🔧 Running Do command for plugin: {node.Text}");
|
||||
var (exitCode, output) = await ExecuteCommand(doCmd);
|
||||
Logger.Log($"Do Output:\n{output}");
|
||||
|
||||
Logger.Log(exitCode == 0 ? "✅ Fix applied successfully." : "❌ Fix failed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"🔧 No Do command found, executing full script.");
|
||||
await ExecutePlugin(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the node is a plugin node.
|
||||
/// 9. Reverts changes for a single plugin node.
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task RestorePlugin(TreeNode node)
|
||||
{
|
||||
if (node?.Tag is string path && File.Exists(path))
|
||||
{
|
||||
var content = File.ReadAllText(path);
|
||||
var commands = ParseCommands(content);
|
||||
|
||||
if (commands.TryGetValue("Undo", out string undoCmd))
|
||||
{
|
||||
Logger.Log($"♻️ Running Undo command for plugin: {node.Text}");
|
||||
var (exitCode, output) = await ExecuteCommand(undoCmd);
|
||||
Logger.Log($"Undo Output:\n{output}");
|
||||
|
||||
Logger.Log(exitCode == 0 ? "✅ Restore successful." : "❌ Restore failed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"⚠️ No Undo command found. Restore not possible.");
|
||||
MessageBox.Show("Restore is not possible for this plugin.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 10. Recursively analyze all checked plugin nodes.
|
||||
public static async Task AnalyzeAll(TreeNode node)
|
||||
{
|
||||
if (node.Checked && node.Tag is string path && File.Exists(path))
|
||||
await AnalyzePlugin(node);
|
||||
|
||||
foreach (TreeNode child in node.Nodes)
|
||||
await AnalyzeAll(child);
|
||||
}
|
||||
|
||||
public static async Task AnalyzeAllPlugins(TreeNodeCollection nodes)
|
||||
{
|
||||
Logger.Log("\n🔌 PLUGIN ANALYSIS", LogLevel.Info);
|
||||
Logger.Log(new string('=', 50), LogLevel.Info);
|
||||
|
||||
foreach (TreeNode node in nodes)
|
||||
await AnalyzeAll(node);
|
||||
}
|
||||
|
||||
/// 11. Recursively apply fixes for all checked plugin nodes.
|
||||
public static async Task FixChecked(TreeNode node)
|
||||
{
|
||||
if (node.Checked && node.Tag is string pluginPath)
|
||||
{
|
||||
var pluginName = Path.GetFileName(pluginPath);
|
||||
var proceed = ShowPluginWarning(pluginName);
|
||||
if (!proceed) return;
|
||||
await FixPlugin(node);
|
||||
}
|
||||
|
||||
foreach (TreeNode child in node.Nodes)
|
||||
await FixChecked(child);
|
||||
}
|
||||
|
||||
/// 12. Return true if the node represents a PowerShell plugin file.
|
||||
public static bool IsPluginNode(TreeNode node)
|
||||
{
|
||||
return node?.Tag is string path && path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows a warning message box when the root plugin node is checked.
|
||||
/// </summary>
|
||||
/// <returns>True if the user confirmed, otherwise false.</returns>
|
||||
/// 13. Show a warning before executing external plugin code.
|
||||
public static bool ShowPluginWarning(string pluginName)
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
$"⚠️ WARNING: The plugin '{pluginName}' is an external script. Its execution is outside this apps responsibility and at your own risk.\n" +
|
||||
"Proceed only if you trust the source of this plugin. Do you want to continue?",
|
||||
"Plugin Activation Warning",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Warning
|
||||
);
|
||||
$"⚠️ WARNING: The plugin '{pluginName}' is an external script. Its execution is outside this app's responsibility and at your own risk.\n" +
|
||||
"Proceed only if you trust the source of this plugin. Do you want to continue?",
|
||||
"Plugin Activation Warning",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Warning
|
||||
);
|
||||
|
||||
return result == DialogResult.Yes; // Return true if "Yes" was clicked
|
||||
return result == DialogResult.Yes;
|
||||
}
|
||||
|
||||
public static bool ShowHelp(TreeNode node)
|
||||
{
|
||||
string info = GetPluginHelpInfo(node);
|
||||
if (!string.IsNullOrEmpty(info))
|
||||
{
|
||||
MessageBox.Show(info, $"Plugin Help: {node.Text}", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the help/info string from the plugin commands section for the given node.
|
||||
/// Assumes node.Tag contains the script path as string.
|
||||
/// </summary>
|
||||
public static string GetPluginHelpInfo(TreeNode node)
|
||||
{
|
||||
if (node?.Tag is string path && File.Exists(path))
|
||||
{
|
||||
string content = File.ReadAllText(path);
|
||||
// Simple parsing to find line starting with "Info=" under [Commands]
|
||||
bool inCommandsSection = false;
|
||||
foreach (var line in content.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var trimmed = line.Trim();
|
||||
|
||||
if (trimmed.StartsWith("[Commands]", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inCommandsSection = true;
|
||||
continue;
|
||||
}
|
||||
if (trimmed.StartsWith("[") && trimmed.EndsWith("]") && inCommandsSection)
|
||||
{
|
||||
// Left commands section
|
||||
break;
|
||||
}
|
||||
if (inCommandsSection && trimmed.StartsWith("Info=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return trimmed.Substring(5).Trim(); // Return the text after "Info="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null; // No info found or invalid node
|
||||
}
|
||||
}
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
|
||||
// indem Sie "*" wie unten gezeigt eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.2.252")]
|
||||
[assembly: AssemblyFileVersion("1.2.252")]
|
||||
[assembly: AssemblyVersion("1.16.156")]
|
||||
[assembly: AssemblyFileVersion("1.16.156")]
|
||||
|
||||
@@ -117,14 +117,14 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="AppIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\AppIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="PredefinedApps" xml:space="preserve">
|
||||
<value>Solitaire,CandyCrush,Netflix, Facebook,Twitter,Instagram,TikTok,Spotify, Skype,OneNote,OneDrive, Mail, Calendar, Weather,News,Maps, Groove, Movies,TV, Phone, Camera,Feedback,FeedbackHub, GetHelp,GetStarted,Messaging,Office,Paint3D,Print3D,StickyNotes,Wallet,YourPhone,3DViewer,Alarms,VoiceRecorder,ToDo,Whiteboard,ZuneMusic,ZuneVideo,3DViewer, DevHome, Copilot,MicrosoftPCManager</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="AppIcon32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\AppIcon32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="AppIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\AppIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
Generated
+34
-7
@@ -35,6 +35,8 @@
|
||||
this.linkGitHub = new System.Windows.Forms.LinkLabel();
|
||||
this.btnDonate = new System.Windows.Forms.Button();
|
||||
this.panelSettings = new System.Windows.Forms.Panel();
|
||||
this.comboBoxCurrency = new System.Windows.Forms.ComboBox();
|
||||
this.comboBoxAmount = new System.Windows.Forms.ComboBox();
|
||||
this.lblCopyright = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
this.panelSettings.SuspendLayout();
|
||||
@@ -58,7 +60,7 @@
|
||||
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.label1.AutoEllipsis = true;
|
||||
this.label1.Location = new System.Drawing.Point(19, 138);
|
||||
this.label1.Location = new System.Drawing.Point(15, 127);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(589, 26);
|
||||
this.label1.TabIndex = 236;
|
||||
@@ -88,12 +90,12 @@
|
||||
// linkGitHub
|
||||
//
|
||||
this.linkGitHub.AutoSize = true;
|
||||
this.linkGitHub.Location = new System.Drawing.Point(38, 173);
|
||||
this.linkGitHub.Location = new System.Drawing.Point(34, 162);
|
||||
this.linkGitHub.Name = "linkGitHub";
|
||||
this.linkGitHub.Size = new System.Drawing.Size(193, 13);
|
||||
this.linkGitHub.Size = new System.Drawing.Size(189, 13);
|
||||
this.linkGitHub.TabIndex = 239;
|
||||
this.linkGitHub.TabStop = true;
|
||||
this.linkGitHub.Text = "https://github.com/builtbybel/CrapFixer";
|
||||
this.linkGitHub.Text = "https://github.com/builtbybel/crapfixer";
|
||||
this.linkGitHub.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkGitHub_LinkClicked);
|
||||
//
|
||||
// btnDonate
|
||||
@@ -104,16 +106,19 @@
|
||||
this.btnDonate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnDonate.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.btnDonate.ForeColor = System.Drawing.Color.White;
|
||||
this.btnDonate.Location = new System.Drawing.Point(61, 85);
|
||||
this.btnDonate.Location = new System.Drawing.Point(226, 91);
|
||||
this.btnDonate.Name = "btnDonate";
|
||||
this.btnDonate.Size = new System.Drawing.Size(207, 39);
|
||||
this.btnDonate.Size = new System.Drawing.Size(101, 22);
|
||||
this.btnDonate.TabIndex = 240;
|
||||
this.btnDonate.Text = "Like CrapFixer? Support future updates on Ko-fi or PayPal";
|
||||
this.btnDonate.Text = "Donate";
|
||||
this.btnDonate.UseVisualStyleBackColor = false;
|
||||
this.btnDonate.Click += new System.EventHandler(this.btnDonate_Click);
|
||||
//
|
||||
// panelSettings
|
||||
//
|
||||
this.panelSettings.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
|
||||
this.panelSettings.Controls.Add(this.comboBoxCurrency);
|
||||
this.panelSettings.Controls.Add(this.comboBoxAmount);
|
||||
this.panelSettings.Controls.Add(this.lblCopyright);
|
||||
this.panelSettings.Controls.Add(this.btnDonate);
|
||||
this.panelSettings.Controls.Add(this.lblHeader);
|
||||
@@ -127,6 +132,26 @@
|
||||
this.panelSettings.Size = new System.Drawing.Size(625, 395);
|
||||
this.panelSettings.TabIndex = 242;
|
||||
//
|
||||
// comboBoxCurrency
|
||||
//
|
||||
this.comboBoxCurrency.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboBoxCurrency.Font = new System.Drawing.Font("Tahoma", 9.25F);
|
||||
this.comboBoxCurrency.FormattingEnabled = true;
|
||||
this.comboBoxCurrency.Location = new System.Drawing.Point(157, 91);
|
||||
this.comboBoxCurrency.Name = "comboBoxCurrency";
|
||||
this.comboBoxCurrency.Size = new System.Drawing.Size(63, 22);
|
||||
this.comboBoxCurrency.TabIndex = 243;
|
||||
//
|
||||
// comboBoxAmount
|
||||
//
|
||||
this.comboBoxAmount.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboBoxAmount.Font = new System.Drawing.Font("Tahoma", 9.25F);
|
||||
this.comboBoxAmount.FormattingEnabled = true;
|
||||
this.comboBoxAmount.Location = new System.Drawing.Point(64, 91);
|
||||
this.comboBoxAmount.Name = "comboBoxAmount";
|
||||
this.comboBoxAmount.Size = new System.Drawing.Size(90, 22);
|
||||
this.comboBoxAmount.TabIndex = 242;
|
||||
//
|
||||
// lblCopyright
|
||||
//
|
||||
this.lblCopyright.AutoSize = true;
|
||||
@@ -163,5 +188,7 @@
|
||||
private System.Windows.Forms.Button btnDonate;
|
||||
private System.Windows.Forms.Panel panelSettings;
|
||||
private System.Windows.Forms.Label lblCopyright;
|
||||
private System.Windows.Forms.ComboBox comboBoxAmount;
|
||||
private System.Windows.Forms.ComboBox comboBoxCurrency;
|
||||
}
|
||||
}
|
||||
|
||||
+38
-29
@@ -1,5 +1,4 @@
|
||||
using CrapFixer;
|
||||
using CFixer.Views;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
@@ -19,6 +18,19 @@ namespace Views
|
||||
{
|
||||
// Update version label
|
||||
this.lblVersionInfo.Text = $"v{Program.GetAppVersion()} ";
|
||||
|
||||
// Populate amount choices
|
||||
comboBoxAmount.Items.AddRange(new object[] { "3.50", "5", "10",
|
||||
"12", "15", "16",
|
||||
"17", "18","20",
|
||||
"25", "30", "35",
|
||||
"40", "50", "60",
|
||||
"70", "80", "100"});
|
||||
comboBoxAmount.SelectedIndex = 2;
|
||||
|
||||
// Populate currency options
|
||||
comboBoxCurrency.Items.AddRange(new object[] { "EUR", "USD", "GBP", "CAD", "AUD", "CHF" });
|
||||
comboBoxCurrency.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void linkGitHub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
@@ -28,37 +40,34 @@ namespace Views
|
||||
|
||||
private void btnDonate_Click(object sender, EventArgs e)
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
"Hi! I'm building CrapFixer solo. Want to support me and help launch Version 1.0?",
|
||||
"Support CrapFixer ❤️",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Information);
|
||||
string amount = comboBoxAmount.SelectedItem?.ToString();
|
||||
string currency = comboBoxCurrency.SelectedItem?.ToString();
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
if (string.IsNullOrEmpty(amount) || string.IsNullOrEmpty(currency))
|
||||
{
|
||||
var donationChoice = MessageBox.Show(
|
||||
"Would you like to donate via PayPal? (Click No for Ko-fi)",
|
||||
"Choose Your Support Method",
|
||||
MessageBoxButtons.YesNoCancel,
|
||||
MessageBoxIcon.Question);
|
||||
|
||||
if (donationChoice == DialogResult.Yes)
|
||||
{
|
||||
System.Diagnostics.Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "https://www.paypal.com/donate/?hosted_button_id=M9DW4VNKH9ECQ",
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
else if (donationChoice == DialogResult.No)
|
||||
{
|
||||
System.Diagnostics.Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "https://ko-fi.com/builtbybel",
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
MessageBox.Show("Please select an amount and a currency.");
|
||||
return;
|
||||
}
|
||||
|
||||
string email = "belim@builtbybel.com";
|
||||
string purpose = Uri.EscapeDataString("Support Development of the CrapFixer app.");
|
||||
|
||||
string returnUrl = Uri.EscapeDataString("https://github.com/Belim/support");
|
||||
string cancelUrl = Uri.EscapeDataString("https://github.com/builtbybel/CrapFixer");
|
||||
|
||||
string url = $"https://www.paypal.com/cgi-bin/webscr?cmd=_donations" +
|
||||
$"&business={Uri.EscapeDataString(email)}" +
|
||||
$"&amount={amount}" +
|
||||
$"¤cy_code={currency}" +
|
||||
$"&item_name={purpose}" +
|
||||
$"&return={returnUrl}" +
|
||||
$"&cancel_return={cancelUrl}";
|
||||
|
||||
System.Diagnostics.Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = url,
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+44
-22
@@ -29,16 +29,18 @@
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.panelSettings = new System.Windows.Forms.Panel();
|
||||
this.btnViveMenu = new System.Windows.Forms.Button();
|
||||
this.btnPluginsMenu = new System.Windows.Forms.Button();
|
||||
this.panelSubContent = new System.Windows.Forms.Panel();
|
||||
this.btnAboutMenu = new System.Windows.Forms.Button();
|
||||
this.btnSettingsMenu = new System.Windows.Forms.Button();
|
||||
this.btnPluginsMenu = new System.Windows.Forms.Button();
|
||||
this.panelSettings.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// panelSettings
|
||||
//
|
||||
this.panelSettings.BackColor = System.Drawing.Color.White;
|
||||
this.panelSettings.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(248)))));
|
||||
this.panelSettings.Controls.Add(this.btnViveMenu);
|
||||
this.panelSettings.Controls.Add(this.btnPluginsMenu);
|
||||
this.panelSettings.Controls.Add(this.panelSubContent);
|
||||
this.panelSettings.Controls.Add(this.btnAboutMenu);
|
||||
@@ -49,15 +51,46 @@
|
||||
this.panelSettings.Size = new System.Drawing.Size(625, 395);
|
||||
this.panelSettings.TabIndex = 243;
|
||||
//
|
||||
// btnViveMenu
|
||||
//
|
||||
this.btnViveMenu.BackColor = System.Drawing.Color.White;
|
||||
this.btnViveMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
|
||||
this.btnViveMenu.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(210)))), ((int)(((byte)(238)))));
|
||||
this.btnViveMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnViveMenu.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnViveMenu.Location = new System.Drawing.Point(14, 88);
|
||||
this.btnViveMenu.Name = "btnViveMenu";
|
||||
this.btnViveMenu.Size = new System.Drawing.Size(100, 32);
|
||||
this.btnViveMenu.TabIndex = 248;
|
||||
this.btnViveMenu.Text = "Features ";
|
||||
this.btnViveMenu.UseVisualStyleBackColor = false;
|
||||
this.btnViveMenu.Click += new System.EventHandler(this.btnViveMenu_Click);
|
||||
//
|
||||
// btnPluginsMenu
|
||||
//
|
||||
this.btnPluginsMenu.BackColor = System.Drawing.Color.White;
|
||||
this.btnPluginsMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
|
||||
this.btnPluginsMenu.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(210)))), ((int)(((byte)(238)))));
|
||||
this.btnPluginsMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnPluginsMenu.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnPluginsMenu.Location = new System.Drawing.Point(14, 48);
|
||||
this.btnPluginsMenu.Name = "btnPluginsMenu";
|
||||
this.btnPluginsMenu.Size = new System.Drawing.Size(100, 32);
|
||||
this.btnPluginsMenu.TabIndex = 247;
|
||||
this.btnPluginsMenu.Text = "Plugins";
|
||||
this.btnPluginsMenu.UseVisualStyleBackColor = false;
|
||||
this.btnPluginsMenu.Click += new System.EventHandler(this.btnPluginsMenu_Click);
|
||||
//
|
||||
// panelSubContent
|
||||
//
|
||||
this.panelSubContent.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.panelSubContent.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
|
||||
this.panelSubContent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.panelSubContent.Location = new System.Drawing.Point(135, 14);
|
||||
this.panelSubContent.Location = new System.Drawing.Point(129, 8);
|
||||
this.panelSubContent.Name = "panelSubContent";
|
||||
this.panelSubContent.Size = new System.Drawing.Size(474, 363);
|
||||
this.panelSubContent.Size = new System.Drawing.Size(487, 378);
|
||||
this.panelSubContent.TabIndex = 246;
|
||||
//
|
||||
// btnAboutMenu
|
||||
@@ -65,11 +98,12 @@
|
||||
this.btnAboutMenu.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnAboutMenu.BackColor = System.Drawing.Color.White;
|
||||
this.btnAboutMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
|
||||
this.btnAboutMenu.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(210)))), ((int)(((byte)(238)))));
|
||||
this.btnAboutMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnAboutMenu.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnAboutMenu.Location = new System.Drawing.Point(14, 343);
|
||||
this.btnAboutMenu.Location = new System.Drawing.Point(14, 354);
|
||||
this.btnAboutMenu.Name = "btnAboutMenu";
|
||||
this.btnAboutMenu.Size = new System.Drawing.Size(107, 34);
|
||||
this.btnAboutMenu.Size = new System.Drawing.Size(100, 32);
|
||||
this.btnAboutMenu.TabIndex = 242;
|
||||
this.btnAboutMenu.Text = "About";
|
||||
this.btnAboutMenu.UseVisualStyleBackColor = false;
|
||||
@@ -79,30 +113,17 @@
|
||||
//
|
||||
this.btnSettingsMenu.BackColor = System.Drawing.Color.White;
|
||||
this.btnSettingsMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
|
||||
this.btnSettingsMenu.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(210)))), ((int)(((byte)(238)))));
|
||||
this.btnSettingsMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnSettingsMenu.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnSettingsMenu.Location = new System.Drawing.Point(14, 13);
|
||||
this.btnSettingsMenu.Location = new System.Drawing.Point(14, 8);
|
||||
this.btnSettingsMenu.Name = "btnSettingsMenu";
|
||||
this.btnSettingsMenu.Size = new System.Drawing.Size(107, 34);
|
||||
this.btnSettingsMenu.Size = new System.Drawing.Size(100, 32);
|
||||
this.btnSettingsMenu.TabIndex = 241;
|
||||
this.btnSettingsMenu.Text = "Settings";
|
||||
this.btnSettingsMenu.UseVisualStyleBackColor = false;
|
||||
this.btnSettingsMenu.Click += new System.EventHandler(this.btnSettingsMenu_Click);
|
||||
//
|
||||
// btnPluginsMenu
|
||||
//
|
||||
this.btnPluginsMenu.BackColor = System.Drawing.Color.White;
|
||||
this.btnPluginsMenu.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(153)))), ((int)(((byte)(180)))), ((int)(((byte)(209)))));
|
||||
this.btnPluginsMenu.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnPluginsMenu.Font = new System.Drawing.Font("Tahoma", 8F);
|
||||
this.btnPluginsMenu.Location = new System.Drawing.Point(14, 53);
|
||||
this.btnPluginsMenu.Name = "btnPluginsMenu";
|
||||
this.btnPluginsMenu.Size = new System.Drawing.Size(107, 34);
|
||||
this.btnPluginsMenu.TabIndex = 247;
|
||||
this.btnPluginsMenu.Text = "Plugins";
|
||||
this.btnPluginsMenu.UseVisualStyleBackColor = false;
|
||||
this.btnPluginsMenu.Click += new System.EventHandler(this.btnPluginsMenu_Click);
|
||||
//
|
||||
// OptionsView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@@ -122,5 +143,6 @@
|
||||
private System.Windows.Forms.Button btnAboutMenu;
|
||||
private System.Windows.Forms.Panel panelSubContent;
|
||||
private System.Windows.Forms.Button btnPluginsMenu;
|
||||
private System.Windows.Forms.Button btnViveMenu;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,10 @@ namespace CFixer.Views
|
||||
{
|
||||
subNavigation.SwitchView(new PluginsView());
|
||||
}
|
||||
|
||||
private void btnViveMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
subNavigation.SwitchView(new ViveView());
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+111
-39
@@ -30,20 +30,26 @@
|
||||
{
|
||||
this.btnPluginInstall = new System.Windows.Forms.Button();
|
||||
this.btnDescription = new System.Windows.Forms.Button();
|
||||
this.listBoxPlugins = new System.Windows.Forms.CheckedListBox();
|
||||
this.progressBarDownload = new System.Windows.Forms.ProgressBar();
|
||||
this.btnPluginOpen = new System.Windows.Forms.Button();
|
||||
this.btnPluginEdit = new System.Windows.Forms.Button();
|
||||
this.btnPluginRemove = new System.Windows.Forms.Button();
|
||||
this.btnPluginSubmit = new System.Windows.Forms.Button();
|
||||
this.btnPluginUpdateAll = new System.Windows.Forms.Button();
|
||||
this.btnHelp = new System.Windows.Forms.Button();
|
||||
this.textSearch = new System.Windows.Forms.TextBox();
|
||||
this.linkPluginUsage = new System.Windows.Forms.LinkLabel();
|
||||
this.listPlugins = new System.Windows.Forms.ListView();
|
||||
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnPluginInstall
|
||||
//
|
||||
this.btnPluginInstall.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnPluginInstall.Location = new System.Drawing.Point(488, 46);
|
||||
this.btnPluginInstall.Location = new System.Drawing.Point(500, 46);
|
||||
this.btnPluginInstall.Name = "btnPluginInstall";
|
||||
this.btnPluginInstall.Size = new System.Drawing.Size(121, 29);
|
||||
this.btnPluginInstall.Size = new System.Drawing.Size(109, 29);
|
||||
this.btnPluginInstall.TabIndex = 7;
|
||||
this.btnPluginInstall.Text = "Install";
|
||||
this.btnPluginInstall.UseVisualStyleBackColor = true;
|
||||
@@ -59,53 +65,40 @@
|
||||
this.btnDescription.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnDescription.Location = new System.Drawing.Point(15, 10);
|
||||
this.btnDescription.Name = "btnDescription";
|
||||
this.btnDescription.Padding = new System.Windows.Forms.Padding(20, 0, 0, 0);
|
||||
this.btnDescription.Padding = new System.Windows.Forms.Padding(20, 0, 100, 0);
|
||||
this.btnDescription.Size = new System.Drawing.Size(594, 25);
|
||||
this.btnDescription.TabIndex = 6;
|
||||
this.btnDescription.Text = "Plugins Gallery (App restart needed after install)";
|
||||
this.btnDescription.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.btnDescription.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// listBoxPlugins
|
||||
//
|
||||
this.listBoxPlugins.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.listBoxPlugins.Font = new System.Drawing.Font("Tahoma", 8.25F);
|
||||
this.listBoxPlugins.FormattingEnabled = true;
|
||||
this.listBoxPlugins.Location = new System.Drawing.Point(15, 44);
|
||||
this.listBoxPlugins.Name = "listBoxPlugins";
|
||||
this.listBoxPlugins.Size = new System.Drawing.Size(457, 340);
|
||||
this.listBoxPlugins.TabIndex = 8;
|
||||
this.listBoxPlugins.SelectedIndexChanged += new System.EventHandler(this.listBoxPlugins_SelectedIndexChanged);
|
||||
//
|
||||
// progressBarDownload
|
||||
//
|
||||
this.progressBarDownload.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.progressBarDownload.Location = new System.Drawing.Point(15, 380);
|
||||
this.progressBarDownload.Name = "progressBarDownload";
|
||||
this.progressBarDownload.Size = new System.Drawing.Size(457, 12);
|
||||
this.progressBarDownload.Size = new System.Drawing.Size(470, 12);
|
||||
this.progressBarDownload.TabIndex = 9;
|
||||
this.progressBarDownload.Visible = false;
|
||||
//
|
||||
// btnPluginOpen
|
||||
// btnPluginEdit
|
||||
//
|
||||
this.btnPluginOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnPluginOpen.Location = new System.Drawing.Point(488, 116);
|
||||
this.btnPluginOpen.Name = "btnPluginOpen";
|
||||
this.btnPluginOpen.Size = new System.Drawing.Size(121, 29);
|
||||
this.btnPluginOpen.TabIndex = 10;
|
||||
this.btnPluginOpen.Text = "Open";
|
||||
this.btnPluginOpen.UseVisualStyleBackColor = true;
|
||||
this.btnPluginOpen.Click += new System.EventHandler(this.btnPluginOpen_Click);
|
||||
this.btnPluginEdit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnPluginEdit.Location = new System.Drawing.Point(500, 151);
|
||||
this.btnPluginEdit.Name = "btnPluginEdit";
|
||||
this.btnPluginEdit.Size = new System.Drawing.Size(109, 29);
|
||||
this.btnPluginEdit.TabIndex = 10;
|
||||
this.btnPluginEdit.Text = "Edit";
|
||||
this.btnPluginEdit.UseVisualStyleBackColor = true;
|
||||
this.btnPluginEdit.Click += new System.EventHandler(this.btnPluginEdit_Click);
|
||||
//
|
||||
// btnPluginRemove
|
||||
//
|
||||
this.btnPluginRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnPluginRemove.Location = new System.Drawing.Point(488, 151);
|
||||
this.btnPluginRemove.Location = new System.Drawing.Point(500, 116);
|
||||
this.btnPluginRemove.Name = "btnPluginRemove";
|
||||
this.btnPluginRemove.Size = new System.Drawing.Size(121, 29);
|
||||
this.btnPluginRemove.Size = new System.Drawing.Size(109, 29);
|
||||
this.btnPluginRemove.TabIndex = 11;
|
||||
this.btnPluginRemove.Text = "Remove";
|
||||
this.btnPluginRemove.UseVisualStyleBackColor = true;
|
||||
@@ -114,9 +107,9 @@
|
||||
// btnPluginSubmit
|
||||
//
|
||||
this.btnPluginSubmit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnPluginSubmit.Location = new System.Drawing.Point(488, 345);
|
||||
this.btnPluginSubmit.Location = new System.Drawing.Point(500, 345);
|
||||
this.btnPluginSubmit.Name = "btnPluginSubmit";
|
||||
this.btnPluginSubmit.Size = new System.Drawing.Size(121, 29);
|
||||
this.btnPluginSubmit.Size = new System.Drawing.Size(109, 29);
|
||||
this.btnPluginSubmit.TabIndex = 12;
|
||||
this.btnPluginSubmit.Text = "Submit Plugin";
|
||||
this.btnPluginSubmit.UseVisualStyleBackColor = true;
|
||||
@@ -125,32 +118,105 @@
|
||||
// btnPluginUpdateAll
|
||||
//
|
||||
this.btnPluginUpdateAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnPluginUpdateAll.Location = new System.Drawing.Point(488, 81);
|
||||
this.btnPluginUpdateAll.Location = new System.Drawing.Point(500, 81);
|
||||
this.btnPluginUpdateAll.Name = "btnPluginUpdateAll";
|
||||
this.btnPluginUpdateAll.Size = new System.Drawing.Size(121, 29);
|
||||
this.btnPluginUpdateAll.Size = new System.Drawing.Size(109, 29);
|
||||
this.btnPluginUpdateAll.TabIndex = 13;
|
||||
this.btnPluginUpdateAll.Text = "Update All";
|
||||
this.btnPluginUpdateAll.UseVisualStyleBackColor = true;
|
||||
this.btnPluginUpdateAll.Click += new System.EventHandler(this.btnPluginUpdateAll_Click);
|
||||
//
|
||||
// btnHelp
|
||||
//
|
||||
this.btnHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnHelp.Location = new System.Drawing.Point(500, 186);
|
||||
this.btnHelp.Name = "btnHelp";
|
||||
this.btnHelp.Size = new System.Drawing.Size(109, 29);
|
||||
this.btnHelp.TabIndex = 14;
|
||||
this.btnHelp.Text = "Help";
|
||||
this.btnHelp.UseVisualStyleBackColor = true;
|
||||
this.btnHelp.Click += new System.EventHandler(this.btnHelp_Click);
|
||||
//
|
||||
// textSearch
|
||||
//
|
||||
this.textSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.textSearch.Location = new System.Drawing.Point(500, 233);
|
||||
this.textSearch.Name = "textSearch";
|
||||
this.textSearch.Size = new System.Drawing.Size(109, 20);
|
||||
this.textSearch.TabIndex = 245;
|
||||
this.textSearch.Text = "Search";
|
||||
this.textSearch.Click += new System.EventHandler(this.textSearch_Click);
|
||||
this.textSearch.TextChanged += new System.EventHandler(this.textSearch_TextChanged);
|
||||
//
|
||||
// linkPluginUsage
|
||||
//
|
||||
this.linkPluginUsage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.linkPluginUsage.AutoSize = true;
|
||||
this.linkPluginUsage.BackColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.linkPluginUsage.Location = new System.Drawing.Point(535, 16);
|
||||
this.linkPluginUsage.Name = "linkPluginUsage";
|
||||
this.linkPluginUsage.Size = new System.Drawing.Size(67, 13);
|
||||
this.linkPluginUsage.TabIndex = 246;
|
||||
this.linkPluginUsage.TabStop = true;
|
||||
this.linkPluginUsage.Text = "Usage notes";
|
||||
this.linkPluginUsage.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkPluginUsage_LinkClicked);
|
||||
//
|
||||
// listPlugins
|
||||
//
|
||||
this.listPlugins.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.listPlugins.CheckBoxes = true;
|
||||
this.listPlugins.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.columnHeader1,
|
||||
this.columnHeader2,
|
||||
this.columnHeader3});
|
||||
this.listPlugins.FullRowSelect = true;
|
||||
this.listPlugins.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
|
||||
this.listPlugins.HideSelection = false;
|
||||
this.listPlugins.Location = new System.Drawing.Point(15, 46);
|
||||
this.listPlugins.Name = "listPlugins";
|
||||
this.listPlugins.Size = new System.Drawing.Size(470, 328);
|
||||
this.listPlugins.TabIndex = 247;
|
||||
this.listPlugins.UseCompatibleStateImageBehavior = false;
|
||||
this.listPlugins.View = System.Windows.Forms.View.Details;
|
||||
this.listPlugins.SelectedIndexChanged += new System.EventHandler(this.listPlugins_SelectedIndexChanged);
|
||||
//
|
||||
// columnHeader1
|
||||
//
|
||||
this.columnHeader1.Text = "Plugin";
|
||||
//
|
||||
// columnHeader2
|
||||
//
|
||||
this.columnHeader2.Text = "Installed";
|
||||
//
|
||||
// columnHeader3
|
||||
//
|
||||
this.columnHeader3.Text = "Type";
|
||||
this.columnHeader3.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
//
|
||||
// PluginsView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.AutoScroll = true;
|
||||
this.BackColor = System.Drawing.Color.White;
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
|
||||
this.Controls.Add(this.listPlugins);
|
||||
this.Controls.Add(this.linkPluginUsage);
|
||||
this.Controls.Add(this.textSearch);
|
||||
this.Controls.Add(this.btnHelp);
|
||||
this.Controls.Add(this.btnPluginUpdateAll);
|
||||
this.Controls.Add(this.btnPluginSubmit);
|
||||
this.Controls.Add(this.btnPluginRemove);
|
||||
this.Controls.Add(this.btnPluginOpen);
|
||||
this.Controls.Add(this.btnPluginEdit);
|
||||
this.Controls.Add(this.progressBarDownload);
|
||||
this.Controls.Add(this.listBoxPlugins);
|
||||
this.Controls.Add(this.btnPluginInstall);
|
||||
this.Controls.Add(this.btnDescription);
|
||||
this.Name = "PluginsView";
|
||||
this.Size = new System.Drawing.Size(625, 395);
|
||||
this.Load += new System.EventHandler(this.PluginsView_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
@@ -158,11 +224,17 @@
|
||||
|
||||
private System.Windows.Forms.Button btnPluginInstall;
|
||||
private System.Windows.Forms.Button btnDescription;
|
||||
private System.Windows.Forms.CheckedListBox listBoxPlugins;
|
||||
private System.Windows.Forms.ProgressBar progressBarDownload;
|
||||
private System.Windows.Forms.Button btnPluginOpen;
|
||||
private System.Windows.Forms.Button btnPluginEdit;
|
||||
private System.Windows.Forms.Button btnPluginRemove;
|
||||
private System.Windows.Forms.Button btnPluginSubmit;
|
||||
private System.Windows.Forms.Button btnPluginUpdateAll;
|
||||
private System.Windows.Forms.Button btnHelp;
|
||||
private System.Windows.Forms.TextBox textSearch;
|
||||
private System.Windows.Forms.LinkLabel linkPluginUsage;
|
||||
private System.Windows.Forms.ListView listPlugins;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader2;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader3;
|
||||
}
|
||||
}
|
||||
|
||||
+231
-71
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@@ -10,8 +11,10 @@ namespace CFixer.Views
|
||||
{
|
||||
public partial class PluginsView : UserControl
|
||||
{
|
||||
private List<PluginEntry> plugins = new List<PluginEntry>();
|
||||
private HashSet<string> installedPlugins = new HashSet<string>();
|
||||
private List<PluginEntry> plugins = new List<PluginEntry>(); // All plugins from the manifest, so full squad
|
||||
private List<PluginEntry> visiblePlugins = new List<PluginEntry>(); // Plugins currently shown in the UI (filtered or not)
|
||||
private HashSet<string> installedPlugins = new HashSet<string>(); // Names of plugins already installed on disk
|
||||
|
||||
private const string manifestUrl = "https://raw.githubusercontent.com/builtbybel/CrapFixer/main/plugins/plugins_manifest.txt";
|
||||
|
||||
public class PluginEntry
|
||||
@@ -31,6 +34,9 @@ namespace CFixer.Views
|
||||
await LoadPlugins();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the currently installed plugins from disk into memory.
|
||||
/// </summary>
|
||||
private void LoadInstalledPlugins()
|
||||
{
|
||||
var pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
|
||||
@@ -43,29 +49,28 @@ namespace CFixer.Views
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads plugins from the remote manifest and displays them.
|
||||
/// </summary>
|
||||
private async Task LoadPlugins()
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadInstalledPlugins();
|
||||
LoadInstalledPlugins(); // Load the plugins already installed on disk, gotta know whats up
|
||||
|
||||
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
// Download the plugin manifest
|
||||
string content = await Task.Run(() => client.DownloadString(manifestUrl));
|
||||
|
||||
// Parse the manifest into our plugins list — all the available plugins decoded!
|
||||
plugins = ParseManifest(content);
|
||||
|
||||
listBoxPlugins.Items.Clear();
|
||||
foreach (var plugin in plugins)
|
||||
{
|
||||
var fileName = Path.GetFileName(plugin.Url);
|
||||
string displayName = plugin.Name;
|
||||
// Sync visiblePlugins with the full list to keep UI and data in perfect harmony
|
||||
visiblePlugins = plugins.ToList();
|
||||
|
||||
if (installedPlugins.Contains(fileName))
|
||||
displayName += " (Installed)";
|
||||
|
||||
listBoxPlugins.Items.Add(displayName);
|
||||
}
|
||||
// Update the ListBox so it shows all the plugins we're tracking right now
|
||||
UpdateVisiblePlugins();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -74,37 +79,61 @@ namespace CFixer.Views
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the remote plugin manifest into a list of PluginEntry objects.
|
||||
/// </summary>
|
||||
private List<PluginEntry> ParseManifest(string content)
|
||||
{
|
||||
var result = new List<PluginEntry>();
|
||||
var lines = content.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
|
||||
PluginEntry current = null;
|
||||
string currentKey = null;
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.StartsWith("[") && line.EndsWith("]"))
|
||||
var trimmedLine = line.Trim();
|
||||
|
||||
if (trimmedLine.StartsWith("[") && trimmedLine.EndsWith("]"))
|
||||
{
|
||||
if (current != null)
|
||||
result.Add(current);
|
||||
|
||||
var name = line.Substring(1, line.Length - 2).Trim();
|
||||
var name = trimmedLine.Substring(1, trimmedLine.Length - 2).Trim();
|
||||
current = new PluginEntry { Name = name };
|
||||
currentKey = null;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(line) && line.Contains("=") && current != null)
|
||||
else if (!string.IsNullOrWhiteSpace(trimmedLine))
|
||||
{
|
||||
var parts = line.Split(new[] { '=' }, 2);
|
||||
var key = parts[0].Trim();
|
||||
var value = parts[1].Trim();
|
||||
|
||||
switch (key)
|
||||
if (trimmedLine.Contains("=") && current != null)
|
||||
{
|
||||
case "description":
|
||||
current.Description = value;
|
||||
break;
|
||||
var parts = trimmedLine.Split(new[] { '=' }, 2);
|
||||
var key = parts[0].Trim();
|
||||
var value = parts[1].Trim();
|
||||
|
||||
case "url":
|
||||
current.Url = value;
|
||||
break;
|
||||
switch (key)
|
||||
{
|
||||
case "description":
|
||||
current.Description = value;
|
||||
currentKey = "description";
|
||||
break;
|
||||
|
||||
case "url":
|
||||
current.Url = value;
|
||||
currentKey = "url";
|
||||
break;
|
||||
|
||||
default:
|
||||
currentKey = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (currentKey == "description" && current != null)
|
||||
{
|
||||
// This line handles multi-line description values.
|
||||
// If the previous key was "description" and the current line does not contain a new key=value pair,
|
||||
// it is considered a continuation of the description.
|
||||
// We append the new line to the existing description, preserving line breaks with "\n".
|
||||
current.Description += "\n" + trimmedLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,10 +144,14 @@ namespace CFixer.Views
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads and installs checked plugins.
|
||||
/// If force is true, existing files will be overwritten.
|
||||
/// </summary>
|
||||
private async Task InstallPlugins(bool force = false)
|
||||
{
|
||||
var checkedIndices = listBoxPlugins.CheckedIndices;
|
||||
if (checkedIndices.Count == 0)
|
||||
var checkedItems = listPlugins.CheckedItems.Cast<ListViewItem>().ToList();
|
||||
if (checkedItems.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please check one or more plugins to download.");
|
||||
return;
|
||||
@@ -129,18 +162,22 @@ namespace CFixer.Views
|
||||
|
||||
progressBarDownload.Visible = true;
|
||||
progressBarDownload.Value = 0;
|
||||
progressBarDownload.Maximum = checkedIndices.Count;
|
||||
progressBarDownload.Maximum = checkedItems.Count;
|
||||
|
||||
int done = 0;
|
||||
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
foreach (int index in checkedIndices)
|
||||
foreach (var item in checkedItems)
|
||||
{
|
||||
var plugin = plugins[index];
|
||||
var plugin = item.Tag as PluginEntry;
|
||||
if (plugin == null)
|
||||
continue;
|
||||
|
||||
string file = Path.Combine(savePath, Path.GetFileName(plugin.Url));
|
||||
|
||||
if (!force && File.Exists(file)) // skip only if not in force‑mode
|
||||
// Skip download if file exists and not forcing overwrite
|
||||
if (!force && File.Exists(file))
|
||||
{
|
||||
progressBarDownload.Value = ++done;
|
||||
continue;
|
||||
@@ -150,7 +187,8 @@ namespace CFixer.Views
|
||||
{
|
||||
await client.DownloadFileTaskAsync(new Uri(plugin.Url), file);
|
||||
installedPlugins.Add(Path.GetFileName(plugin.Url));
|
||||
listBoxPlugins.Items[index] = plugin.Name + " (Installed)";
|
||||
item.SubItems[1].Text = "Yes"; // Update Installed column
|
||||
//item.Checked = true; // Ensure checked
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -164,73 +202,190 @@ namespace CFixer.Views
|
||||
progressBarDownload.Visible = false;
|
||||
}
|
||||
|
||||
|
||||
private async void btnPluginInstall_Click(object sender, EventArgs e)
|
||||
{
|
||||
await InstallPlugins(force: false); // skip installed
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates all plugins by selecting all and force-downloading them.
|
||||
/// </summary>
|
||||
private async void btnPluginUpdateAll_Click(object sender, EventArgs e)
|
||||
{
|
||||
// check every item
|
||||
for (int i = 0; i < listBoxPlugins.Items.Count; i++)
|
||||
listBoxPlugins.SetItemChecked(i, true);
|
||||
// Check all items in the list
|
||||
foreach (ListViewItem item in listPlugins.Items)
|
||||
{
|
||||
item.Checked = true;
|
||||
}
|
||||
|
||||
// Force install (overwrite even if already installed)
|
||||
await InstallPlugins(force: true);
|
||||
|
||||
// Update the status of all plugins to "Updated"
|
||||
foreach (ListViewItem item in listPlugins.Items)
|
||||
{
|
||||
item.SubItems[1].Text = "Updated";
|
||||
}
|
||||
|
||||
await InstallPlugins(force: true); // always overwrite
|
||||
MessageBox.Show("All plugins updated.");
|
||||
}
|
||||
|
||||
private void listBoxPlugins_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
int index = listBoxPlugins.SelectedIndex;
|
||||
if (index >= 0 && index < plugins.Count)
|
||||
{
|
||||
btnDescription.Text = plugins[index].Description;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnPluginOpen_Click(object sender, EventArgs e)
|
||||
{
|
||||
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
|
||||
|
||||
if (Directory.Exists(pluginPath))
|
||||
{
|
||||
System.Diagnostics.Process.Start("explorer.exe", pluginPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("The plugins folder does not exist yet.");
|
||||
}
|
||||
}
|
||||
|
||||
private void btnPluginRemove_Click(object sender, EventArgs e)
|
||||
{
|
||||
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
|
||||
var indices = listBoxPlugins.CheckedIndices.Cast<int>().ToList();
|
||||
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
|
||||
|
||||
if (indices.Count == 0)
|
||||
var checkedItems = listPlugins.CheckedItems.Cast<ListViewItem>().ToList();
|
||||
|
||||
if (checkedItems.Count == 0)
|
||||
{
|
||||
MessageBox.Show("No plugins selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (int i in indices)
|
||||
foreach (var item in checkedItems)
|
||||
{
|
||||
var plugin = plugins[i];
|
||||
var plugin = item.Tag as PluginEntry;
|
||||
if (plugin == null)
|
||||
continue;
|
||||
|
||||
string path = Path.Combine(pluginPath, Path.GetFileName(plugin.Url));
|
||||
|
||||
if (File.Exists(path))
|
||||
File.Delete(path);
|
||||
|
||||
listBoxPlugins.Items[i] = plugin.Name; // Remove (Installed) tag
|
||||
listBoxPlugins.SetItemChecked(i, false); // Uncheck
|
||||
installedPlugins.Remove(Path.GetFileName(plugin.Url));
|
||||
item.SubItems[1].Text = "No";
|
||||
item.Checked = false;
|
||||
}
|
||||
|
||||
MessageBox.Show("Selected plugins removed.");
|
||||
}
|
||||
|
||||
private void btnPluginEdit_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (listPlugins.SelectedItems.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please select a plugin first.");
|
||||
return;
|
||||
}
|
||||
|
||||
var plugin = listPlugins.SelectedItems[0].Tag as PluginEntry;
|
||||
if (plugin == null) return;
|
||||
|
||||
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins", Path.GetFileName(plugin.Url));
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
MessageBox.Show("Plugin file not found. Please install the plugin first.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
var editor = ext == ".ps1" ? "powershell_ise.exe" : "notepad.exe";
|
||||
Process.Start(editor, $"\"{path}\"");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Could not open plugin: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows plugin information in a MessageBox.
|
||||
/// </summary>
|
||||
private void btnHelp_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (listPlugins.SelectedItems.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please select a plugin first.");
|
||||
return;
|
||||
}
|
||||
|
||||
var plugin = listPlugins.SelectedItems[0].Tag as PluginEntry;
|
||||
if (plugin != null)
|
||||
{
|
||||
MessageBox.Show(plugin.Description, $"Info: {plugin.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
private void listPlugins_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (listPlugins.SelectedItems.Count == 0)
|
||||
return;
|
||||
|
||||
var plugin = listPlugins.SelectedItems[0].Tag as PluginEntry;
|
||||
if (plugin != null)
|
||||
{
|
||||
btnDescription.Text = plugin.Description;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the ListView with filtered plugin entries,
|
||||
/// including name, install status, and plugin type.
|
||||
/// Type is determined by plugin name ("(NX)" means native plugin),
|
||||
/// or file extension (.ps1 = Powershell; others = Other).
|
||||
/// </summary>
|
||||
private void UpdateVisiblePlugins(string query = "")
|
||||
{
|
||||
visiblePlugins = plugins
|
||||
.Where(p =>
|
||||
p.Name.ToLower().Contains(query) ||
|
||||
(p.Description?.ToLower() ?? "").Contains(query))
|
||||
.ToList();
|
||||
|
||||
listPlugins.Items.Clear();
|
||||
|
||||
foreach (var plugin in visiblePlugins)
|
||||
{
|
||||
var fileName = Path.GetFileName(plugin.Url);
|
||||
bool isInstalled = installedPlugins.Contains(fileName);
|
||||
|
||||
// Determine plugin type
|
||||
string type;
|
||||
if (plugin.Name.Trim().EndsWith("(NX)", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
type = "NX";
|
||||
}
|
||||
else if (Path.GetExtension(plugin.Url).Equals(".ps1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
type = "Powershell";
|
||||
}
|
||||
else
|
||||
{
|
||||
type = "Other";
|
||||
}
|
||||
|
||||
var item = new ListViewItem(plugin.Name);
|
||||
item.SubItems.Add(isInstalled ? "Yes" : "No");
|
||||
item.SubItems.Add(type);
|
||||
item.Tag = plugin;
|
||||
item.Checked = isInstalled;
|
||||
|
||||
listPlugins.Items.Add(item);
|
||||
}
|
||||
|
||||
// Auto-resize columns to fit header and content
|
||||
foreach (ColumnHeader column in listPlugins.Columns)
|
||||
{
|
||||
column.Width = -2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void textSearch_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
string query = textSearch.Text.Trim().ToLower();
|
||||
UpdateVisiblePlugins(query);
|
||||
}
|
||||
|
||||
private void textSearch_Click(object sender, EventArgs e)
|
||||
{
|
||||
textSearch.Text = string.Empty;
|
||||
}
|
||||
|
||||
private void btnPluginSubmit_Click(object sender, EventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
|
||||
@@ -239,5 +394,10 @@ namespace CFixer.Views
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
|
||||
private void linkPluginUsage_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
Process.Start("https://github.com/builtbybel/CrapFixer/blob/main/plugins/DemoPluginPack.ps1");
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+21
-10
@@ -31,31 +31,29 @@
|
||||
this.checkSaveToINI = new System.Windows.Forms.CheckBox();
|
||||
this.checkBox2 = new System.Windows.Forms.CheckBox();
|
||||
this.button1 = new System.Windows.Forms.Button();
|
||||
this.checkInstallIcons = new System.Windows.Forms.CheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// checkSaveToINI
|
||||
//
|
||||
this.checkSaveToINI.AutoSize = true;
|
||||
this.checkSaveToINI.Checked = true;
|
||||
this.checkSaveToINI.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.checkSaveToINI.Location = new System.Drawing.Point(15, 44);
|
||||
this.checkSaveToINI.Location = new System.Drawing.Point(15, 48);
|
||||
this.checkSaveToINI.Name = "checkSaveToINI";
|
||||
this.checkSaveToINI.Size = new System.Drawing.Size(135, 17);
|
||||
this.checkSaveToINI.Size = new System.Drawing.Size(148, 17);
|
||||
this.checkSaveToINI.TabIndex = 0;
|
||||
this.checkSaveToINI.Text = "Save settings to INI file";
|
||||
this.checkSaveToINI.Text = "Save all settings to INI file";
|
||||
this.checkSaveToINI.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// checkBox2
|
||||
//
|
||||
this.checkBox2.AutoSize = true;
|
||||
this.checkBox2.Checked = true;
|
||||
this.checkBox2.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.checkBox2.Enabled = false;
|
||||
this.checkBox2.Location = new System.Drawing.Point(15, 67);
|
||||
this.checkBox2.Location = new System.Drawing.Point(15, 71);
|
||||
this.checkBox2.Name = "checkBox2";
|
||||
this.checkBox2.Size = new System.Drawing.Size(211, 17);
|
||||
this.checkBox2.Size = new System.Drawing.Size(236, 35);
|
||||
this.checkBox2.TabIndex = 1;
|
||||
this.checkBox2.Text = "Activate Plugins for PowerShell Tooling";
|
||||
this.checkBox2.Text = "Activate Plugins for PowerShell Tooling (Super Plugins)";
|
||||
this.checkBox2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// button1
|
||||
@@ -74,11 +72,23 @@
|
||||
this.button1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.button1.UseVisualStyleBackColor = false;
|
||||
//
|
||||
// checkInstallIcons
|
||||
//
|
||||
this.checkInstallIcons.AutoSize = true;
|
||||
this.checkInstallIcons.Location = new System.Drawing.Point(15, 112);
|
||||
this.checkInstallIcons.Name = "checkInstallIcons";
|
||||
this.checkInstallIcons.Size = new System.Drawing.Size(265, 17);
|
||||
this.checkInstallIcons.TabIndex = 4;
|
||||
this.checkInstallIcons.Text = "Download optional icons to enhance navigation UI";
|
||||
this.checkInstallIcons.UseVisualStyleBackColor = true;
|
||||
this.checkInstallIcons.CheckedChanged += new System.EventHandler(this.checkInstallIcons_CheckedChanged);
|
||||
//
|
||||
// SettingsView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.BackColor = System.Drawing.Color.White;
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
|
||||
this.Controls.Add(this.checkInstallIcons);
|
||||
this.Controls.Add(this.button1);
|
||||
this.Controls.Add(this.checkBox2);
|
||||
this.Controls.Add(this.checkSaveToINI);
|
||||
@@ -95,5 +105,6 @@
|
||||
private System.Windows.Forms.CheckBox checkSaveToINI;
|
||||
private System.Windows.Forms.CheckBox checkBox2;
|
||||
private System.Windows.Forms.Button button1;
|
||||
private System.Windows.Forms.CheckBox checkInstallIcons;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CFixer.Views
|
||||
@@ -10,6 +13,7 @@ namespace CFixer.Views
|
||||
{
|
||||
InitializeComponent();
|
||||
LoadSettings();
|
||||
CheckIfIconsInstalled();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -38,5 +42,72 @@ namespace CFixer.Views
|
||||
{
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
private void CheckIfIconsInstalled()
|
||||
{
|
||||
string iconFolder = Path.Combine(Application.StartupPath, "icons");
|
||||
string[] requiredIcons = { "fixer.png", "options.png", "restore.png" };
|
||||
|
||||
bool allIconsExist = requiredIcons.All(icon => File.Exists(Path.Combine(iconFolder, icon)));
|
||||
|
||||
checkInstallIcons.Enabled = !allIconsExist;
|
||||
}
|
||||
|
||||
private async void checkInstallIcons_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
"By default, buttons have no icons to reduce app size. Enable this to download and display navigation icons." +
|
||||
"\nWould you like to install it now?",
|
||||
"Icons Pack Detected",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Information
|
||||
);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
string iconFolder = Path.Combine(Application.StartupPath, "icons");
|
||||
if (!Directory.Exists(iconFolder))
|
||||
Directory.CreateDirectory(iconFolder);
|
||||
|
||||
string[] iconFiles = new string[]
|
||||
{
|
||||
"fixer.png",
|
||||
"options.png",
|
||||
"restore.png"
|
||||
};
|
||||
|
||||
string baseUrl = "https://raw.githubusercontent.com/builtbybel/CrapFixer/main/icons/";
|
||||
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
foreach (string fileName in iconFiles)
|
||||
{
|
||||
string url = baseUrl + fileName;
|
||||
string localPath = Path.Combine(iconFolder, fileName);
|
||||
await wc.DownloadFileTaskAsync(new Uri(url), localPath);
|
||||
}
|
||||
}
|
||||
|
||||
MessageBox.Show(
|
||||
"All icons have been successfully installed in the 'icons' folder!\n\n💖 Love CrapFixer? Consider supporting me with a small donation to keep this tool alive and improving!",
|
||||
"Icons Installed",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Information
|
||||
);
|
||||
|
||||
// Restart the application to apply changes
|
||||
Application.Restart();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("❌ An error occurred while downloading the icons:\n" + ex.Message,
|
||||
"Download Failed",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+218
@@ -0,0 +1,218 @@
|
||||
namespace CFixer.Views
|
||||
{
|
||||
partial class ViveView
|
||||
{
|
||||
/// <summary>
|
||||
/// Erforderliche Designervariable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Verwendete Ressourcen bereinigen.
|
||||
/// </summary>
|
||||
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Vom Komponenten-Designer generierter Code
|
||||
|
||||
/// <summary>
|
||||
/// Erforderliche Methode für die Designerunterstützung.
|
||||
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.dataGridView = new System.Windows.Forms.DataGridView();
|
||||
this.EnabledColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
|
||||
this.NameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.IdColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.StatusColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.InfoColumn = new System.Windows.Forms.DataGridViewLinkColumn();
|
||||
this.btnApply = new System.Windows.Forms.Button();
|
||||
this.btnDescription = new System.Windows.Forms.Button();
|
||||
this.linkPluginUsage = new System.Windows.Forms.LinkLabel();
|
||||
this.txtCustomIds = new System.Windows.Forms.TextBox();
|
||||
this.lblCustomIds = new System.Windows.Forms.Label();
|
||||
this.btnApplyCustom = new System.Windows.Forms.Button();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// dataGridView
|
||||
//
|
||||
this.dataGridView.AllowUserToAddRows = false;
|
||||
this.dataGridView.AllowUserToDeleteRows = false;
|
||||
this.dataGridView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.dataGridView.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
|
||||
this.dataGridView.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
|
||||
this.dataGridView.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
|
||||
this.dataGridView.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None;
|
||||
this.dataGridView.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None;
|
||||
this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.EnabledColumn,
|
||||
this.NameColumn,
|
||||
this.IdColumn,
|
||||
this.StatusColumn,
|
||||
this.InfoColumn});
|
||||
this.dataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
|
||||
this.dataGridView.Location = new System.Drawing.Point(15, 46);
|
||||
this.dataGridView.Name = "dataGridView";
|
||||
this.dataGridView.RowHeadersVisible = false;
|
||||
this.dataGridView.Size = new System.Drawing.Size(470, 305);
|
||||
this.dataGridView.TabIndex = 0;
|
||||
this.dataGridView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellContentClick);
|
||||
//
|
||||
// EnabledColumn
|
||||
//
|
||||
this.EnabledColumn.FillWeight = 57.38248F;
|
||||
this.EnabledColumn.HeaderText = "";
|
||||
this.EnabledColumn.Name = "EnabledColumn";
|
||||
this.EnabledColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.EnabledColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
//
|
||||
// NameColumn
|
||||
//
|
||||
this.NameColumn.FillWeight = 203.0457F;
|
||||
this.NameColumn.HeaderText = "Feature";
|
||||
this.NameColumn.Name = "NameColumn";
|
||||
//
|
||||
// IdColumn
|
||||
//
|
||||
this.IdColumn.FillWeight = 79.85728F;
|
||||
this.IdColumn.HeaderText = "ID";
|
||||
this.IdColumn.Name = "IdColumn";
|
||||
//
|
||||
// StatusColumn
|
||||
//
|
||||
this.StatusColumn.FillWeight = 79.85728F;
|
||||
this.StatusColumn.HeaderText = "Status";
|
||||
this.StatusColumn.Name = "StatusColumn";
|
||||
this.StatusColumn.ReadOnly = true;
|
||||
//
|
||||
// InfoColumn
|
||||
//
|
||||
this.InfoColumn.FillWeight = 79.85728F;
|
||||
this.InfoColumn.HeaderText = "Info";
|
||||
this.InfoColumn.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline;
|
||||
this.InfoColumn.Name = "InfoColumn";
|
||||
this.InfoColumn.ReadOnly = true;
|
||||
this.InfoColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.InfoColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
//
|
||||
// btnApply
|
||||
//
|
||||
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnApply.Location = new System.Drawing.Point(500, 47);
|
||||
this.btnApply.Name = "btnApply";
|
||||
this.btnApply.Size = new System.Drawing.Size(109, 29);
|
||||
this.btnApply.TabIndex = 8;
|
||||
this.btnApply.Text = "Apply selected";
|
||||
this.btnApply.UseVisualStyleBackColor = true;
|
||||
this.btnApply.Click += new System.EventHandler(this.btnViveApply_Click);
|
||||
//
|
||||
// btnDescription
|
||||
//
|
||||
this.btnDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnDescription.AutoEllipsis = true;
|
||||
this.btnDescription.BackColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.btnDescription.FlatAppearance.BorderColor = System.Drawing.Color.Gainsboro;
|
||||
this.btnDescription.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnDescription.Location = new System.Drawing.Point(15, 10);
|
||||
this.btnDescription.Name = "btnDescription";
|
||||
this.btnDescription.Padding = new System.Windows.Forms.Padding(20, 0, 100, 0);
|
||||
this.btnDescription.Size = new System.Drawing.Size(594, 25);
|
||||
this.btnDescription.TabIndex = 9;
|
||||
this.btnDescription.Text = "ViVe Tool";
|
||||
this.btnDescription.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.btnDescription.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// linkPluginUsage
|
||||
//
|
||||
this.linkPluginUsage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.linkPluginUsage.AutoSize = true;
|
||||
this.linkPluginUsage.BackColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.linkPluginUsage.Location = new System.Drawing.Point(535, 16);
|
||||
this.linkPluginUsage.Name = "linkPluginUsage";
|
||||
this.linkPluginUsage.Size = new System.Drawing.Size(56, 13);
|
||||
this.linkPluginUsage.TabIndex = 247;
|
||||
this.linkPluginUsage.TabStop = true;
|
||||
this.linkPluginUsage.Text = "More infos";
|
||||
this.linkPluginUsage.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkPluginUsage_LinkClicked);
|
||||
//
|
||||
// txtCustomIds
|
||||
//
|
||||
this.txtCustomIds.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txtCustomIds.Location = new System.Drawing.Point(77, 357);
|
||||
this.txtCustomIds.Multiline = true;
|
||||
this.txtCustomIds.Name = "txtCustomIds";
|
||||
this.txtCustomIds.Size = new System.Drawing.Size(408, 24);
|
||||
this.txtCustomIds.TabIndex = 248;
|
||||
//
|
||||
// lblCustomIds
|
||||
//
|
||||
this.lblCustomIds.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.lblCustomIds.AutoSize = true;
|
||||
this.lblCustomIds.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblCustomIds.Location = new System.Drawing.Point(12, 363);
|
||||
this.lblCustomIds.Name = "lblCustomIds";
|
||||
this.lblCustomIds.Size = new System.Drawing.Size(59, 13);
|
||||
this.lblCustomIds.TabIndex = 249;
|
||||
this.lblCustomIds.Text = "Custom Ids";
|
||||
//
|
||||
// btnApplyCustom
|
||||
//
|
||||
this.btnApplyCustom.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnApplyCustom.Location = new System.Drawing.Point(500, 355);
|
||||
this.btnApplyCustom.Name = "btnApplyCustom";
|
||||
this.btnApplyCustom.Size = new System.Drawing.Size(109, 29);
|
||||
this.btnApplyCustom.TabIndex = 250;
|
||||
this.btnApplyCustom.Text = "Apply Custom";
|
||||
this.btnApplyCustom.UseVisualStyleBackColor = true;
|
||||
this.btnApplyCustom.Click += new System.EventHandler(this.btnApplyCustom_Click);
|
||||
//
|
||||
// ViveView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(251)))), ((int)(((byte)(251)))));
|
||||
this.Controls.Add(this.btnApplyCustom);
|
||||
this.Controls.Add(this.lblCustomIds);
|
||||
this.Controls.Add(this.txtCustomIds);
|
||||
this.Controls.Add(this.linkPluginUsage);
|
||||
this.Controls.Add(this.btnDescription);
|
||||
this.Controls.Add(this.btnApply);
|
||||
this.Controls.Add(this.dataGridView);
|
||||
this.Name = "ViveView";
|
||||
this.Size = new System.Drawing.Size(625, 395);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.DataGridView dataGridView;
|
||||
private System.Windows.Forms.Button btnApply;
|
||||
private System.Windows.Forms.Button btnDescription;
|
||||
private System.Windows.Forms.LinkLabel linkPluginUsage;
|
||||
private System.Windows.Forms.TextBox txtCustomIds;
|
||||
private System.Windows.Forms.Label lblCustomIds;
|
||||
private System.Windows.Forms.Button btnApplyCustom;
|
||||
private System.Windows.Forms.DataGridViewCheckBoxColumn EnabledColumn;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn NameColumn;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn IdColumn;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn StatusColumn;
|
||||
private System.Windows.Forms.DataGridViewLinkColumn InfoColumn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CFixer.Views
|
||||
{
|
||||
public partial class ViveView : UserControl
|
||||
{
|
||||
private List<ViveFeature> featureList;
|
||||
private string viveToolPath;
|
||||
|
||||
public ViveView()
|
||||
{
|
||||
InitializeComponent();
|
||||
IsViveToolAvailable();
|
||||
InitFeatureList();
|
||||
LoadFeaturesToGrid();
|
||||
|
||||
// Fire and forget async call
|
||||
_ = UpdateFeatureStatusFromSystem();
|
||||
}
|
||||
|
||||
private void IsViveToolAvailable()
|
||||
{
|
||||
string pluginsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
|
||||
|
||||
var viveFolder = Directory.GetDirectories(pluginsDir)
|
||||
.FirstOrDefault(dir => Path.GetFileName(dir).ToLower().StartsWith("vive"));
|
||||
|
||||
if (viveFolder == null)
|
||||
{
|
||||
viveToolPath = null;
|
||||
btnDescription.Text = "Enable experimental and hidden features (Disabled)";
|
||||
return;
|
||||
}
|
||||
|
||||
string exePath = Path.Combine(viveFolder, "ViVeTool.exe");
|
||||
if (File.Exists(exePath))
|
||||
{
|
||||
viveToolPath = exePath;
|
||||
btnDescription.Text = "Enable experimental and hidden features (Enabled)";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes hardcoded feature list with names, IDs and default states.
|
||||
/// </summary>
|
||||
private void InitFeatureList()
|
||||
{
|
||||
featureList = new List<ViveFeature>
|
||||
{
|
||||
new ViveFeature
|
||||
{
|
||||
Ids = new List<int> {47205210, 49221331, 49381526, 49402389, 49820095, 55495322, 48433719},
|
||||
Name = "Enable the redesigned Windows 11 Start menu",
|
||||
InfoUrl = "https://www.neowin.net/guides/how-to-enable-the-redesigned-windows-11-start-menu/",
|
||||
Enabled = false
|
||||
},
|
||||
new ViveFeature
|
||||
{
|
||||
Ids = new List<int> {52467192,53079680},
|
||||
Name = "Enable Text extractor in Snipping Tool",
|
||||
InfoUrl = "https://blogs.windows.com/windows-insider/2025/04/15/text-extractor-in-snipping-tool-begins-rolling-out-to-windows-insiders/",
|
||||
Enabled = false
|
||||
}
|
||||
,new ViveFeature
|
||||
{
|
||||
Ids = new List<int> {45624564},
|
||||
Name = "Enable Drag Tray Share UI",
|
||||
InfoUrl = "https://www.neowin.net/news/windows-11-is-getting-a-quirky-new-way-to-share-files/",
|
||||
Enabled = false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the feature list into the DataGridView UI.
|
||||
/// </summary>
|
||||
private void LoadFeaturesToGrid()
|
||||
{
|
||||
dataGridView.Rows.Clear();
|
||||
|
||||
foreach (var feature in featureList)
|
||||
{
|
||||
int rowIndex = dataGridView.Rows.Add();
|
||||
var row = dataGridView.Rows[rowIndex];
|
||||
|
||||
row.Cells["EnabledColumn"].Value = feature.Enabled;
|
||||
row.Cells["NameColumn"].Value = feature.Name;
|
||||
row.Cells["IdColumn"].Value = feature.IdsAsString;
|
||||
row.Cells["InfoColumn"].Value = feature.InfoUrl;
|
||||
row.Cells["StatusColumn"].Value = "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes ViVeTool with given feature IDs and state.
|
||||
/// </summary>
|
||||
private void ApplyFeature(List<int> ids, bool enable)
|
||||
{
|
||||
if (string.IsNullOrEmpty(viveToolPath))
|
||||
{
|
||||
MessageBox.Show("ViVeTool not found. Please ensure it is installed in the plugins folder.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string action = enable ? "/enable" : "/disable";
|
||||
string idArg = string.Join(",", ids);
|
||||
string args = $"{action} /id:{idArg}";
|
||||
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = viveToolPath,
|
||||
Arguments = args,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true,
|
||||
Verb = "runas" // Run as administrator
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the currently selected states from the DataGridView to the system using ViVeTool.
|
||||
/// </summary>
|
||||
private async void btnViveApply_Click(object sender, EventArgs e)
|
||||
{
|
||||
for (int i = 0; i < dataGridView.Rows.Count; i++)
|
||||
{
|
||||
var row = dataGridView.Rows[i];
|
||||
if (row.IsNewRow) continue;
|
||||
|
||||
bool isEnabled = Convert.ToBoolean(row.Cells["EnabledColumn"].Value);
|
||||
string idText = row.Cells["IdColumn"].Value.ToString();
|
||||
List<int> ids = idText.Split(',').Select(s => int.Parse(s.Trim())).ToList();
|
||||
|
||||
ApplyFeature(ids, isEnabled);
|
||||
}
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
await UpdateFeatureStatusFromSystem(); // Refresh the status after applying changes
|
||||
|
||||
MessageBox.Show("Features have been applied.", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries the current system state using ViVeTool and returns a map of ID => isEnabled.
|
||||
/// </summary>
|
||||
// Pro ID ein Query machen, um den Status exakt zu ermitteln
|
||||
private Dictionary<int, bool> QueryCurrentFeatureStates()
|
||||
{
|
||||
var statusMap = new Dictionary<int, bool>();
|
||||
|
||||
if (string.IsNullOrEmpty(viveToolPath))
|
||||
{
|
||||
MessageBox.Show("ViVeTool not found. Please ensure it is installed in the plugins folder.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return statusMap;
|
||||
}
|
||||
|
||||
var allIds = featureList.SelectMany(f => f.Ids).Distinct();
|
||||
|
||||
foreach (int id in allIds)
|
||||
{
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = viveToolPath,
|
||||
Arguments = $"/query /id:{id}",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (Process proc = Process.Start(psi))
|
||||
{
|
||||
string output = proc.StandardOutput.ReadToEnd();
|
||||
proc.WaitForExit();
|
||||
|
||||
bool enabled = output.Contains("Enabled");
|
||||
statusMap[id] = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
return statusMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously updates the grid checkboxes and status labels to reflect actual feature states on the system.
|
||||
/// </summary>
|
||||
private async Task UpdateFeatureStatusFromSystem()
|
||||
{
|
||||
// Run QueryCurrentFeatureStates on a background thread
|
||||
var systemStatus = await Task.Run(() => QueryCurrentFeatureStates());
|
||||
|
||||
// Update UI on the UI thread
|
||||
if (dataGridView.InvokeRequired)
|
||||
{
|
||||
dataGridView.Invoke(new Action(() =>
|
||||
{
|
||||
UpdateGridWithStatus(systemStatus);
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateGridWithStatus(systemStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the grid rows with the given status dictionary.
|
||||
/// </summary>
|
||||
private void UpdateGridWithStatus(Dictionary<int, bool> systemStatus)
|
||||
{
|
||||
foreach (DataGridViewRow row in dataGridView.Rows)
|
||||
{
|
||||
if (row.IsNewRow) continue;
|
||||
|
||||
string idText = row.Cells["IdColumn"].Value.ToString();
|
||||
var ids = idText.Split(',').Select(s => int.Parse(s.Trim())).ToList();
|
||||
|
||||
int enabledCount = ids.Count(id => systemStatus.ContainsKey(id) && systemStatus[id]);
|
||||
|
||||
string status = "Disabled";
|
||||
if (enabledCount == ids.Count)
|
||||
status = "All Enabled";
|
||||
else if (enabledCount > 0)
|
||||
status = "Partially Enabled";
|
||||
|
||||
row.Cells["StatusColumn"].Value = status;
|
||||
}
|
||||
}
|
||||
|
||||
private void dataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
if (e.ColumnIndex == dataGridView.Columns["InfoColumn"].Index && e.RowIndex >= 0)
|
||||
{
|
||||
var url = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value?.ToString();
|
||||
if (!string.IsNullOrEmpty(url))
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = url,
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Failed to open link:\n{ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single ViVe feature group.
|
||||
/// </summary>
|
||||
public class ViveFeature
|
||||
{
|
||||
public List<int> Ids { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public string InfoUrl { get; set; }
|
||||
|
||||
public string IdsAsString => string.Join(",", Ids);
|
||||
}
|
||||
|
||||
private void linkPluginUsage_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
MessageBox.Show("This plugin uses ViVeTool to enable hidden Windows features.\n" +
|
||||
"Please download ViVeTool (e.g. 'ViVeTool-v0.3.x-IntelAmd') from:\n" +
|
||||
"https://github.com/thebookisclosed/ViVe/releases\n" +
|
||||
"Extract it and place the contents into a subfolder inside the 'plugins' directory.\n\n");
|
||||
}
|
||||
|
||||
private void btnApplyCustom_Click(object sender, EventArgs e)
|
||||
{
|
||||
string input = txtCustomIds.Text;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
MessageBox.Show("Please enter one or more feature IDs.", "Invalid Input", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse input (e.g., "123,456,789")
|
||||
var idList = new List<int>();
|
||||
var parts = input.Split(',');
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (int.TryParse(part.Trim(), out int id))
|
||||
{
|
||||
idList.Add(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show($"Invalid ID: '{part}'", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (idList.Count == 0)
|
||||
{
|
||||
MessageBox.Show("No valid IDs found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask whether to enable or disable
|
||||
var result = MessageBox.Show(
|
||||
$"Do you want to ENABLE these features?\n\n{string.Join(", ", idList)}\n\n" +
|
||||
"Yes = Enable\nNo = Disable\nCancel = Abort",
|
||||
"Confirm Action",
|
||||
MessageBoxButtons.YesNoCancel,
|
||||
MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.Cancel) return;
|
||||
|
||||
bool enable = (result == DialogResult.Yes);
|
||||
|
||||
ApplyFeature(idList, enable);
|
||||
|
||||
MessageBox.Show("Custom feature action sent to ViVeTool.", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="EnabledColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="NameColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="IdColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="StatusColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="InfoColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="EnabledColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="NameColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="IdColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="StatusColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="InfoColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -1,11 +1,9 @@
|
||||
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">it's called CrapFixer. let that clean in🧽<a href="https://t.co/UP2iLnAgif">https://t.co/UP2iLnAgif</a><a href="https://twitter.com/hashtag/CrapFixer?src=hash&ref_src=twsrc%5Etfw">#CrapFixer</a> <a href="https://twitter.com/hashtag/Windows?src=hash&ref_src=twsrc%5Etfw">#Windows</a> <a href="https://twitter.com/hashtag/Windows11?src=hash&ref_src=twsrc%5Etfw">#Windows11</a> <a href="https://twitter.com/hashtag/app?src=hash&ref_src=twsrc%5Etfw">#app</a> <a href="https://twitter.com/hashtag/microsoft?src=hash&ref_src=twsrc%5Etfw">#microsoft</a> <a href="https://t.co/OMruEjvuUb">pic.twitter.com/OMruEjvuUb</a></p>— Belim (@builtbybel) <a href="https://twitter.com/builtbybel/status/1917594071582773272?ref_src=twsrc%5Etfw">April 30, 2025</a></blockquote>
|
||||
|
||||
|
||||
# Crap F🧼xer
|
||||
# Crap F🧼xer – Fixes the crap Windows leaves behind.
|
||||
|
||||
# The tool that says what everyone's thinking
|
||||
|
||||
## The tool Microsoft would build if they hated bloatware as much as we do
|
||||
## The tool that says what everyone's thinking
|
||||
|
||||
Remember the days when you'd run a registry cleaner even if you didn't really need it? (Or maybe we did need it? I was probably too young to figure that out - too young for that crap 😅) <br>Back then, cleaner tools like CCleaner were everywhere; it felt like every other tech forum had a "top 10 Windows Optimizers" list.
|
||||
|
||||
@@ -15,9 +13,9 @@ This is my personal little IT toolbox that I've been using for years to clean up
|
||||
|
||||
CrapFixer still looks like something straight out of the Windows XP era (maybe Crap Cleaner 😄) - and honestly, that's exactly the vibe I was going for. Sometimes simple just beats fancy. Two clicks: 'Analyze', check the results, 'Fix' - done. No drama, no bloat.
|
||||
|
||||
While cleaning up my GitHub (30+ repos down to 20 now), I also cleaned up thousands of lines of old code. Some projects come and go, but CrapFixer stays. It's fast, simple, and basically bulletproof. I haven't managed to break anything yet. 😉 <br>If you like old-school tools that just work, you're gonna feel right at home. <br>If there's enough interest, I'll also commit the updated code to GitHub soon.
|
||||
While cleaning up my GitHub (30+ repos down to 20 now), I also cleaned up thousands of lines of old code. Some projects come and go, but CrapFixer stays. It's fast, simple, and basically bulletproof. I haven't managed to break anything yet. 😉 <br>If you like old-school tools that just work, you're gonna feel right at home. <br>
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
<details>
|
||||
@@ -41,7 +39,7 @@ If you're curious about the personal story behind this project and others...
|
||||
- **Gray** items = Already optimized
|
||||
|
||||
3. **Apply Fixes**
|
||||
Smash the **"Run CFixer!"** button to apply the recommended tweaks.
|
||||
Smash the **"Run Fixer"** button to apply the recommended tweaks.
|
||||
|
||||
> ⚠️ **Tip:** To view what a tweak does you can **Right-Click** on an item and select **Help** or hit **F1**.
|
||||
> The help system also includes an online lookup that will search the tweak online for you.
|
||||
|
||||
+90
-60
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>CrapFixer Update Check</title>
|
||||
<title>Crap Fixer Update Check</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f3f6fd;
|
||||
@@ -60,56 +60,53 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.donate {
|
||||
margin-top: 2rem;
|
||||
padding: 1.5rem;
|
||||
background-color: #e7f5ec;
|
||||
border-left: 6px solid #4caf50;
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
.donate-box {
|
||||
font-family: Verdana, Geneva, sans-serif;
|
||||
font-size: 13px;
|
||||
background-color: #fffde5;
|
||||
border: 1px solid #ccc;
|
||||
padding: 15px;
|
||||
max-width: 340px;
|
||||
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
|
||||
margin-top: 2rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.donate strong {
|
||||
display: block;
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.donate-box h3 {
|
||||
margin-top: 0;
|
||||
font-size: 14px;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.donate a {
|
||||
margin-top: 1rem;
|
||||
display: inline-block;
|
||||
padding: 0.6rem 1.2rem;
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
.donate-box a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.donate a:hover {
|
||||
background-color: #388e3c;
|
||||
}
|
||||
.donate-box a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.project-follow {
|
||||
margin-top: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.project-follow {
|
||||
margin-top: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.project-follow a {
|
||||
padding: 0.8rem 1.5rem;
|
||||
background: #24292f;
|
||||
color: white;
|
||||
border-radius: var(--radius);
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
transition: background 0.3s ease;
|
||||
display: inline-block;
|
||||
}
|
||||
.project-follow a {
|
||||
padding: 0.8rem 1.5rem;
|
||||
background: #24292f;
|
||||
color: white;
|
||||
border-radius: 12px;
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
transition: background 0.3s ease;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.project-follow a:hover {
|
||||
background: #0366d6;
|
||||
}
|
||||
|
||||
.project-follow a:hover {
|
||||
background: #0366d6;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
body {
|
||||
@@ -129,21 +126,39 @@
|
||||
<!-- Main Content -->
|
||||
<p id="status">Checking version...</p>
|
||||
|
||||
<div class="donate">
|
||||
<strong>💖 Support CrapFixer</strong>
|
||||
Every donation helps me provide more updates. – Thanks, Belim 🙏
|
||||
<br /><br />
|
||||
<a href="https://www.paypal.com/donate/?hosted_button_id=M9DW4VNKH9ECQ" target="_blank">💸 PayPal</a>
|
||||
<a href="https://ko-fi.com/builtbybel" target="_blank" style="background-color: #ff5f5f;">☕ Ko-fi</a>
|
||||
</div>
|
||||
<div class="donate-box">
|
||||
<h3>How can I help?</h3>
|
||||
<p>
|
||||
If you like this software, you can help by <a href="https://twitter.com/intent/tweet?text=Still%20cleaning%20up%20Windows%20like%20it%E2%80%99s%202005.%20CrapFixer%20fixes%20the%20crap%20Windows%20leaves%20behind.%20https%3A%2F%2Fgithub.com%2Fbuiltbybel%2FCrapFixer" target="_blank">tweeting about it</a> or <strong>supporting the project</strong> with a donation.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Although this software is free, any donations — large or small — are greatly appreciated :)
|
||||
</p>
|
||||
|
||||
<form action="https://www.paypal.com/donate" method="post" target="_blank" style="margin-top: 10px;">
|
||||
<input type="hidden" name="hosted_button_id" value="M9DW4VNKH9ECQ" />
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" name="submit" alt="Donate with PayPal" />
|
||||
</form>
|
||||
|
||||
<p style="margin-top: 1rem;">
|
||||
Or support me with a coffee: <a href="https://ko-fi.com/builtbybel" target="_blank">☕ Ko-fi</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 1rem;">
|
||||
Just like the good old tools from back in the day — built with care, running on caffeine and community support ☕💾
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="project-follow">
|
||||
<a href="https://github.com/builtbybel/CrapFixer" target="_blank">🐙 Follow CrapFixer on GitHub</a>
|
||||
</div>
|
||||
|
||||
<div class="project-follow">
|
||||
<a href="https://github.com/builtbybel/CrapFixer" target="_blank">🐙 View on GitHub</a>
|
||||
</div>
|
||||
|
||||
<!-- Update Logic Script -->
|
||||
<script>
|
||||
const latestVersion = "1.5.282";
|
||||
const latestVersion = "1.30.243";
|
||||
|
||||
function compareVersions(v1, v2) {
|
||||
const a = v1.split(".").map(Number);
|
||||
@@ -154,7 +169,13 @@
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
<!-- Changelog link -->
|
||||
function openChangelog(version) {
|
||||
const url = `https://github.com/builtbybel/CrapFixer/releases/tag/${version}`;
|
||||
window.open(url, "changelogWindow", "width=800,height=600,resizable=yes,scrollbars=yes");
|
||||
}
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const userVersion = params.get("version");
|
||||
|
||||
@@ -167,13 +188,22 @@
|
||||
const result = compareVersions(userVersion, latestVersion);
|
||||
|
||||
if (result < 0) {
|
||||
status.innerHTML = `⚠️ Your version (${userVersion}) is outdated.<br><strong>Latest version:</strong> ${latestVersion}<br><a href="https://github.com/builtbybel/CrapFixer/releases">⬇️ Download here</a>`;
|
||||
status.innerHTML = `
|
||||
⚠️ Your version (${userVersion}) is outdated.<br>
|
||||
<strong>Latest version:</strong> ${latestVersion}<br>
|
||||
<a href="https://github.com/builtbybel/CrapFixer/releases" target="_blank">⬇️ Download here</a>
|
||||
|
|
||||
<a href="#" onclick="openChangelog('${latestVersion}')">📄 View Changelog</a>
|
||||
`;
|
||||
} else if (result === 0) {
|
||||
status.innerHTML = `✅ Your version (${userVersion}) is up to date.`;
|
||||
status.innerHTML = `✅ Your version (${userVersion}) is up to date.<br>
|
||||
<a href="#" onclick="openChangelog('${latestVersion}')">📄 View Changelog</a>`;
|
||||
} else {
|
||||
status.innerHTML = `✅ Your version (${userVersion}) is newer than the official release (${latestVersion}).<br><em>Note: You may be using a development build.</em>`;
|
||||
status.innerHTML = `✅ Your version (${userVersion}) is newer than the official release (${latestVersion}).<br><em>Note: You may be using a development build.</em><br>
|
||||
<a href="#" onclick="openChangelog('${latestVersion}')">📄 View Changelog</a>`;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -1,6 +1,9 @@
|
||||
# Whitelist entries (do not flag these)
|
||||
!GetHelp
|
||||
|
||||
# Global hide via wildcard. Remove ! to unhide all.
|
||||
!*.*
|
||||
|
||||
# Bloatware patterns
|
||||
Solitaire
|
||||
CandyCrush
|
||||
|
||||
@@ -12,6 +12,7 @@ url=https://raw.githubusercontent.com/builtbybel/Crapfixer/refs/heads/main/plugi
|
||||
|
||||
[Remove Windows AI]
|
||||
description=Disables and removes AI-related features and integrations in Windows.
|
||||
Developer: zoicware | Web: https://github.com/zoicware/RemoveWindowsAI
|
||||
url=https://raw.githubusercontent.com/builtbybel/Crapfixer/refs/heads/main/plugins/Remove Windows AI.ps1
|
||||
|
||||
[Restart Explorer]
|
||||
|
||||
Reference in New Issue
Block a user