-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move files from EA to Public. #1036
Conversation
WalkthroughThe recent updates to the HandheldCompanion project focus on enhancing thread safety, refining synchronization, and optimizing performance. Changes include the transformation of classes to static, significant method revisions, and improved error handling. The updates span across various components such as GPUs, devices, and UI elements, aiming to streamline operations and increase the robustness of the application. Changes
Recent Review DetailsConfiguration used: CodeRabbit UI Files selected for processing (39)
Files not summarized due to errors (3)
Files skipped from review due to trivial changes (8)
Additional Context UsedLanguageTool (64)
Additional comments not posted (78)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 12
Actionable comments outside the diff hunks (3)
README.md (3)
Line range hint
10-10
: Correct the spelling of "available" in the description of motion control settings.- Settings availible for racing, 1st and 3rd person gaming and emulator support. + Settings available for racing, 1st and 3rd person gaming and emulator support.
Line range hint
11-11
: Correct the spelling of "information" in the description of Quicktools overlay.- with easy access to various settings and informatio such as TDP, Auto TDP, GPU, Screen Hz, ... + with easy access to various settings and information such as TDP, Auto TDP, GPU, Screen Hz, ...
Line range hint
37-37
: Correct the use of "it's" to "its" in the description of supported devices.- AYA Neo Air and it's different versions + AYA Neo Air and its different versions
UseHighDPIAwareness.IsOn = selectedProfile.HighDPIAware; | ||
// Compatibility settings | ||
UseFullscreenOptimizations.IsOn = selectedProfile.FullScreenOptimization; | ||
UseHighDPIAwareness.IsOn = selectedProfile.HighDPIAware; | ||
|
||
// Layout settings | ||
Toggle_ControllerLayout.IsOn = selectedProfile.LayoutEnabled; | ||
// Layout settings | ||
Toggle_ControllerLayout.IsOn = selectedProfile.LayoutEnabled; | ||
|
||
// power profile | ||
PowerProfile powerProfile = PowerProfileManager.GetProfile(selectedProfile.PowerProfile); | ||
powerProfile.Check(this); | ||
// power profile | ||
PowerProfile powerProfile = PowerProfileManager.GetProfile(selectedProfile.PowerProfile); | ||
powerProfile.Check(this); | ||
|
||
// display warnings | ||
WarningContent.Text = EnumUtils.GetDescriptionFromEnumValue(selectedProfile.ErrorCode); | ||
// display warnings | ||
WarningContent.Text = EnumUtils.GetDescriptionFromEnumValue(selectedProfile.ErrorCode); | ||
|
||
switch (selectedProfile.ErrorCode) | ||
{ | ||
default: | ||
case ProfileErrorCode.None: | ||
WarningBorder.Visibility = Visibility.Collapsed; | ||
cB_Whitelist.IsEnabled = true; | ||
switch (selectedProfile.ErrorCode) | ||
{ | ||
default: | ||
case ProfileErrorCode.None: | ||
WarningBorder.Visibility = Visibility.Collapsed; | ||
cB_Whitelist.IsEnabled = true; | ||
|
||
// wrapper | ||
cB_Wrapper_Injection.IsEnabled = true; | ||
cB_Wrapper_Redirection.IsEnabled = true; | ||
break; | ||
// wrapper | ||
cB_Wrapper_Injection.IsEnabled = true; | ||
cB_Wrapper_Redirection.IsEnabled = true; | ||
break; | ||
|
||
case ProfileErrorCode.Running: // application is running | ||
case ProfileErrorCode.MissingExecutable: // profile has no executable | ||
case ProfileErrorCode.MissingPath: // profile has no path | ||
case ProfileErrorCode.Default: // profile is default | ||
WarningBorder.Visibility = Visibility.Visible; | ||
cB_Whitelist.IsEnabled = false; | ||
cB_Wrapper.IsEnabled = false; | ||
|
||
// wrapper | ||
cB_Wrapper_Injection.IsEnabled = false; | ||
cB_Wrapper_Redirection.IsEnabled = false; | ||
break; | ||
case ProfileErrorCode.Running: // application is running | ||
case ProfileErrorCode.MissingExecutable: // profile has no executable | ||
case ProfileErrorCode.MissingPath: // profile has no path | ||
case ProfileErrorCode.Default: // profile is default | ||
WarningBorder.Visibility = Visibility.Visible; | ||
cB_Whitelist.IsEnabled = false; | ||
cB_Wrapper.IsEnabled = false; | ||
|
||
// wrapper | ||
cB_Wrapper_Injection.IsEnabled = false; | ||
cB_Wrapper_Redirection.IsEnabled = false; | ||
break; | ||
|
||
case ProfileErrorCode.MissingPermission: | ||
WarningBorder.Visibility = Visibility.Visible; | ||
cB_Whitelist.IsEnabled = true; | ||
case ProfileErrorCode.MissingPermission: | ||
WarningBorder.Visibility = Visibility.Visible; | ||
cB_Whitelist.IsEnabled = true; | ||
|
||
// wrapper | ||
cB_Wrapper_Injection.IsEnabled = true; | ||
cB_Wrapper_Redirection.IsEnabled = false; | ||
break; | ||
} | ||
// wrapper | ||
cB_Wrapper_Injection.IsEnabled = true; | ||
cB_Wrapper_Redirection.IsEnabled = false; | ||
break; | ||
} | ||
|
||
// update dropdown lists | ||
cB_Profiles.Items.Refresh(); | ||
cb_SubProfilePicker.Items.Refresh(); | ||
}); | ||
// update dropdown lists | ||
cB_Profiles.Items.Refresh(); | ||
cb_SubProfilePicker.Items.Refresh(); | ||
}); | ||
} | ||
finally | ||
{ | ||
profileLock.Exit(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review complex method with multiple UI updates and locking.
This method is quite complex and performs multiple UI updates. It's crucial to ensure that the locking mechanism (profileLock
) is correctly implemented to avoid deadlocks or unnecessary blocking. Additionally, consider refactoring this method to improve readability and maintainability.
if (!isEnabled) | ||
{ | ||
selectedProfile.RSREnabled = false; | ||
selectedProfile.IntegerScalingEnabled = false; | ||
|
||
RSRToggle.IsOn = false; | ||
IntegerScalingToggle.IsOn = false; | ||
RSRToggle.IsOn = false; | ||
IntegerScalingToggle.IsOn = false; | ||
} | ||
} | ||
} | ||
break; | ||
// RSR is incompatible with RIS and IS | ||
case UpdateGraphicsSettingsSource.RadeonSuperResolution: | ||
{ | ||
selectedProfile.RSREnabled = isEnabled; | ||
if (isEnabled) | ||
break; | ||
// RSR is incompatible with RIS and IS | ||
case UpdateGraphicsSettingsSource.RadeonSuperResolution: | ||
{ | ||
selectedProfile.RISEnabled = false; | ||
selectedProfile.IntegerScalingEnabled = false; | ||
|
||
RISToggle.IsOn = false; | ||
IntegerScalingToggle.IsOn = false; | ||
|
||
// RSR does not support ScalingMode.Center | ||
if (selectedProfile.ScalingMode == 2) | ||
selectedProfile.RSREnabled = isEnabled; | ||
if (isEnabled) | ||
{ | ||
selectedProfile.ScalingMode = 1; | ||
GPUScalingComboBox.SelectedIndex = 1; | ||
selectedProfile.RISEnabled = false; | ||
selectedProfile.IntegerScalingEnabled = false; | ||
|
||
RISToggle.IsOn = false; | ||
IntegerScalingToggle.IsOn = false; | ||
|
||
// RSR does not support ScalingMode.Center | ||
if (selectedProfile.ScalingMode == 2) | ||
{ | ||
selectedProfile.ScalingMode = 1; | ||
GPUScalingComboBox.SelectedIndex = 1; | ||
} | ||
} | ||
} | ||
} | ||
break; | ||
// Image Sharpening is incompatible with RSR | ||
case UpdateGraphicsSettingsSource.RadeonImageSharpening: | ||
{ | ||
selectedProfile.RISEnabled = isEnabled; | ||
if (isEnabled) | ||
break; | ||
// Image Sharpening is incompatible with RSR | ||
case UpdateGraphicsSettingsSource.RadeonImageSharpening: | ||
{ | ||
selectedProfile.RSREnabled = false; | ||
selectedProfile.RISEnabled = isEnabled; | ||
if (isEnabled) | ||
{ | ||
selectedProfile.RSREnabled = false; | ||
|
||
RSRToggle.IsOn = false; | ||
RSRToggle.IsOn = false; | ||
} | ||
} | ||
} | ||
break; | ||
break; | ||
|
||
// Integer Scaling is incompatible with RSR | ||
case UpdateGraphicsSettingsSource.IntegerScaling: | ||
{ | ||
selectedProfile.IntegerScalingEnabled = isEnabled; | ||
if (isEnabled) | ||
// Integer Scaling is incompatible with RSR | ||
case UpdateGraphicsSettingsSource.IntegerScaling: | ||
{ | ||
selectedProfile.RSREnabled = false; | ||
selectedProfile.IntegerScalingEnabled = isEnabled; | ||
if (isEnabled) | ||
{ | ||
selectedProfile.RSREnabled = false; | ||
|
||
RSRToggle.IsOn = false; | ||
RSRToggle.IsOn = false; | ||
} | ||
} | ||
} | ||
break; | ||
break; | ||
} | ||
} | ||
finally | ||
{ | ||
graphicLock.Exit(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review method handling graphics settings updates with conditional logic.
This method handles various graphics settings and applies conditional logic based on the settings source. It's important to ensure that the logic is correct and that incompatible settings are appropriately managed. Consider simplifying this method to improve clarity and reduce the potential for errors.
public static void Start() | ||
{ | ||
// monitor profile files | ||
profileWatcher = new FileSystemWatcher | ||
{ | ||
Path = ProfilesPath, | ||
EnableRaisingEvents = true, | ||
IncludeSubdirectories = true, | ||
Filter = "*.json", | ||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | ||
}; | ||
profileWatcher.Created += ProfileCreated; | ||
profileWatcher.Deleted += ProfileDeleted; | ||
|
||
// process existing profiles | ||
string[] fileEntries = Directory.GetFiles(ProfilesPath, "*.json", SearchOption.AllDirectories); | ||
foreach (string fileName in fileEntries) | ||
ProcessProfile(fileName, false); | ||
|
||
// check for default profile | ||
if (!HasDefault()) | ||
{ | ||
Layout deviceLayout = IDevice.GetCurrent().DefaultLayout.Clone() as Layout; | ||
Profile defaultProfile = new() | ||
{ | ||
Name = DefaultName, | ||
Default = true, | ||
Enabled = false, | ||
Layout = deviceLayout, | ||
LayoutTitle = LayoutTemplate.DefaultLayout.Name, | ||
LayoutEnabled = true | ||
}; | ||
|
||
UpdateOrCreateProfile(defaultProfile, UpdateSource.Creation); | ||
} | ||
|
||
IsInitialized = true; | ||
Initialized?.Invoke(); | ||
|
||
LogManager.LogInformation("{0} has started", "ProfileManager"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure proper error handling in the Start
method.
The Start
method lacks error handling for operations that could potentially fail, such as file operations and event subscriptions. Consider adding try-catch blocks around these operations to handle possible exceptions and ensure the application remains stable.
public static Profile GetProfileFromPath(string path, bool ignoreStatus) | ||
{ | ||
// check if favorite sub profile exists for path | ||
Profile profile = subProfiles.FirstOrDefault(pr => pr.Path == path && pr.IsFavoriteSubProfile); | ||
|
||
// get main profile from path instead | ||
if (profile is null) | ||
profile = profiles.Values.FirstOrDefault(a => a.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase)); | ||
|
||
if (profile is null) | ||
{ | ||
// otherwise, get profile from executable | ||
string fileName = Path.GetFileName(path); | ||
profile = profiles.Values.FirstOrDefault(a => a.Executable.Equals(fileName, StringComparison.InvariantCultureIgnoreCase)); | ||
|
||
if (profile is null) | ||
return GetDefault(); | ||
} | ||
|
||
// ignore profile status (enabled/disabled) | ||
if (ignoreStatus) | ||
return profile; | ||
|
||
return profile.Enabled ? profile : GetDefault(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimize the retrieval of profiles in GetProfileFromPath
.
The method GetProfileFromPath
performs multiple searches on the profiles collection, which could be optimized. Consider consolidating the conditions into a single LINQ query to reduce complexity and improve performance.
- Profile profile = subProfiles.FirstOrDefault(pr => pr.Path == path && pr.IsFavoriteSubProfile);
- if (profile is null)
- profile = profiles.Values.FirstOrDefault(a => a.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase));
- if (profile is null)
- profile = profiles.Values.FirstOrDefault(a => a.Executable.Equals(fileName, StringComparison.InvariantCultureIgnoreCase));
+ Profile profile = subProfiles.FirstOrDefault(pr => pr.Path == path && pr.IsFavoriteSubProfile)
+ ?? profiles.Values.FirstOrDefault(a => a.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase) || a.Executable.Equals(fileName, StringComparison.InvariantCultureIgnoreCase));
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
public static Profile GetProfileFromPath(string path, bool ignoreStatus) | |
{ | |
// check if favorite sub profile exists for path | |
Profile profile = subProfiles.FirstOrDefault(pr => pr.Path == path && pr.IsFavoriteSubProfile); | |
// get main profile from path instead | |
if (profile is null) | |
profile = profiles.Values.FirstOrDefault(a => a.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase)); | |
if (profile is null) | |
{ | |
// otherwise, get profile from executable | |
string fileName = Path.GetFileName(path); | |
profile = profiles.Values.FirstOrDefault(a => a.Executable.Equals(fileName, StringComparison.InvariantCultureIgnoreCase)); | |
if (profile is null) | |
return GetDefault(); | |
} | |
// ignore profile status (enabled/disabled) | |
if (ignoreStatus) | |
return profile; | |
return profile.Enabled ? profile : GetDefault(); | |
} | |
public static Profile GetProfileFromPath(string path, bool ignoreStatus) | |
{ | |
// check if favorite sub profile exists for path | |
string fileName = Path.GetFileName(path); | |
Profile profile = subProfiles.FirstOrDefault(pr => pr.Path == path && pr.IsFavoriteSubProfile) | |
?? profiles.Values.FirstOrDefault(a => a.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase) || a.Executable.Equals(fileName, StringComparison.InvariantCultureIgnoreCase)); | |
if (profile is null) | |
return GetDefault(); | |
// ignore profile status (enabled/disabled) | |
if (ignoreStatus) | |
return profile; | |
return profile.Enabled ? profile : GetDefault(); | |
} |
public static void CycleSubProfiles(bool previous = false) | ||
{ | ||
if (currentProfile == null) | ||
return; | ||
// called using previousSubProfile/nextSubProfile hotkeys | ||
List<Profile> subProfilesList = new(); | ||
subProfilesList.Add(GetProfileForSubProfile(currentProfile)); // adds main profile as sub profile | ||
subProfilesList.AddRange(GetSubProfilesFromPath(currentProfile.Path, false).ToList()); // adds all sub profiles | ||
|
||
// if profile does not have sub profiles -> do nothing | ||
if (subProfilesList.Count <= 1) | ||
return; | ||
|
||
// get index of currently applied profile | ||
int currentIndex = subProfilesList.IndexOf(currentProfile); | ||
int newIndex = currentIndex; | ||
|
||
// previous? decrement, next? increment | ||
if (previous) | ||
newIndex -= 1; | ||
else | ||
newIndex += 1; | ||
|
||
// ensure index is within list bounds, wrap if needed | ||
newIndex = (newIndex + subProfilesList.Count) % subProfilesList.Count; | ||
|
||
// if for whatever reason index is out of bound -> return | ||
if (newIndex < 0 || newIndex >= subProfilesList.Count) | ||
return; | ||
|
||
// apply profile | ||
Profile profileToApply = subProfilesList[newIndex]; | ||
UpdateOrCreateProfile(profileToApply); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review the logic for cycling subprofiles in CycleSubProfiles
.
The method CycleSubProfiles
contains complex logic for cycling through profiles, which might be error-prone. Specifically, the method modifies the index without checking if the list is empty, which could lead to an ArgumentOutOfRangeException
. Add checks to ensure the list is not empty before modifying the index.
lock (updateLock) | ||
{ | ||
// UI thread (async) | ||
// UI thread |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tip
Codebase Verification
The review comment suggested ensuring that updateLock
is used consistently and safely throughout the LayoutPage.xaml.cs
class. However, the script output indicates that updateLock
is declared and used in only one lock
statement. This raises a concern about whether updateLock
is sufficiently utilized for synchronization purposes across the class, especially if there are other operations that require thread safety.
- The declaration of
updateLock
and its use in alock
statement are the only occurrences found. - No further usage of
updateLock
in other parts of the class was detected, which might suggest insufficient synchronization if other parts of the class are also accessing shared resources.
Given this, it seems appropriate to flag this for further review or adjustments by the development team.
Analysis chain
Switching from ScopedLock
to lock
simplifies synchronization. Ensure updateLock
is used consistently and safely throughout the class.
Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for all occurrences of `updateLock` to ensure it's used safely and consistently.
rg --type cs 'updateLock' -- 'HandheldCompanion/Views/Pages/LayoutPage.xaml.cs'
Length of output: 145
protected new ctl_telemetry_data TelemetryData = new(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initialization of TelemetryData
should be moved inside the constructor to ensure it's properly initialized with the rest of the object's state.
- protected new ctl_telemetry_data TelemetryData = new();
+ protected new ctl_telemetry_data TelemetryData;
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
protected new ctl_telemetry_data TelemetryData = new(); | |
protected new ctl_telemetry_data TelemetryData; |
private ctl_telemetry_data GetTelemetry() | ||
{ | ||
if (!IsInitialized) | ||
return TelemetryData; | ||
|
||
return Execute(() => | ||
{ | ||
return IGCLBackend.GetTelemetry(deviceIdx); | ||
}, TelemetryData); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method GetTelemetry
should handle the case where TelemetryData
is not initialized before use. Consider initializing TelemetryData
in the constructor.
+ if (TelemetryData == null) TelemetryData = new ctl_telemetry_data();
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
private ctl_telemetry_data GetTelemetry() | |
{ | |
if (!IsInitialized) | |
return TelemetryData; | |
return Execute(() => | |
{ | |
return IGCLBackend.GetTelemetry(deviceIdx); | |
}, TelemetryData); | |
} | |
private ctl_telemetry_data GetTelemetry() | |
{ | |
if (TelemetryData == null) TelemetryData = new ctl_telemetry_data(); | |
if (!IsInitialized) | |
return TelemetryData; | |
return Execute(() => | |
{ | |
return IGCLBackend.GetTelemetry(deviceIdx); | |
}, TelemetryData); | |
} |
SliderSensitivityX.Value = ProfilesPage.selectedProfile.MotionSensivityX; | ||
SliderSensitivityY.Value = ProfilesPage.selectedProfile.MotionSensivityY; | ||
tb_ProfileAimingDownSightsMultiplier.Value = ProfilesPage.selectedProfile.AimingSightsMultiplier; | ||
Toggle_FlickStick.IsOn = ProfilesPage.selectedProfile.FlickstickEnabled; | ||
tb_ProfileFlickDuration.Value = ProfilesPage.selectedProfile.FlickstickDuration * 1000; | ||
tb_ProfileStickSensitivity.Value = ProfilesPage.selectedProfile.FlickstickSensivity; | ||
|
||
// todo: improve me ? | ||
ProfilesPageHotkey.inputsChord.State = ProfilesPage.selectedProfile.AimingSightsTrigger.Clone() as ButtonState; | ||
ProfilesPageHotkey.DrawInput(); | ||
|
||
// temp | ||
StackCurve.Children.Clear(); | ||
foreach (KeyValuePair<double, double> elem in ProfilesPage.selectedProfile.MotionSensivityArray) | ||
{ | ||
Tag = elem.Key, | ||
Width = 8, | ||
MaxHeight = StackCurve.Height, | ||
Height = height, | ||
VerticalAlignment = VerticalAlignment.Bottom, | ||
Background = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentLowBrush"], | ||
BorderThickness = new Thickness(0), | ||
BorderBrush = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentHighBrush"], | ||
IsEnabled = false // prevent the control from being clickable | ||
}; | ||
|
||
StackCurve.Children.Add(thumb); | ||
} | ||
}); | ||
// skip first item ? | ||
if (elem.Key == 0) | ||
continue; | ||
|
||
double height = elem.Value * StackCurve.Height; | ||
Thumb thumb = new Thumb | ||
{ | ||
Tag = elem.Key, | ||
Width = 8, | ||
MaxHeight = StackCurve.Height, | ||
Height = height, | ||
VerticalAlignment = VerticalAlignment.Bottom, | ||
Background = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentLowBrush"], | ||
BorderThickness = new Thickness(0), | ||
BorderBrush = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentHighBrush"], | ||
IsEnabled = false // prevent the control from being clickable | ||
}; | ||
|
||
StackCurve.Children.Add(thumb); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The UI update logic inside the Dispatcher.Invoke call is extensive. While the logic appears correct, it's quite dense and could benefit from being broken down into smaller, more manageable methods. This would improve readability and maintainability.
+ private void UpdateUIWithProfileSettings()
+ {
+ SliderSensitivityX.Value = ProfilesPage.selectedProfile.MotionSensivityX;
+ // Add other UI updates here...
+ }
+
- Application.Current.Dispatcher.Invoke(() =>
- {
- SliderSensitivityX.Value = ProfilesPage.selectedProfile.MotionSensivityX;
- // Other UI updates...
- });
+ Application.Current.Dispatcher.Invoke(UpdateUIWithProfileSettings);
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
SliderSensitivityX.Value = ProfilesPage.selectedProfile.MotionSensivityX; | |
SliderSensitivityY.Value = ProfilesPage.selectedProfile.MotionSensivityY; | |
tb_ProfileAimingDownSightsMultiplier.Value = ProfilesPage.selectedProfile.AimingSightsMultiplier; | |
Toggle_FlickStick.IsOn = ProfilesPage.selectedProfile.FlickstickEnabled; | |
tb_ProfileFlickDuration.Value = ProfilesPage.selectedProfile.FlickstickDuration * 1000; | |
tb_ProfileStickSensitivity.Value = ProfilesPage.selectedProfile.FlickstickSensivity; | |
// todo: improve me ? | |
ProfilesPageHotkey.inputsChord.State = ProfilesPage.selectedProfile.AimingSightsTrigger.Clone() as ButtonState; | |
ProfilesPageHotkey.DrawInput(); | |
// temp | |
StackCurve.Children.Clear(); | |
foreach (KeyValuePair<double, double> elem in ProfilesPage.selectedProfile.MotionSensivityArray) | |
{ | |
Tag = elem.Key, | |
Width = 8, | |
MaxHeight = StackCurve.Height, | |
Height = height, | |
VerticalAlignment = VerticalAlignment.Bottom, | |
Background = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentLowBrush"], | |
BorderThickness = new Thickness(0), | |
BorderBrush = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentHighBrush"], | |
IsEnabled = false // prevent the control from being clickable | |
}; | |
StackCurve.Children.Add(thumb); | |
} | |
}); | |
// skip first item ? | |
if (elem.Key == 0) | |
continue; | |
double height = elem.Value * StackCurve.Height; | |
Thumb thumb = new Thumb | |
{ | |
Tag = elem.Key, | |
Width = 8, | |
MaxHeight = StackCurve.Height, | |
Height = height, | |
VerticalAlignment = VerticalAlignment.Bottom, | |
Background = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentLowBrush"], | |
BorderThickness = new Thickness(0), | |
BorderBrush = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentHighBrush"], | |
IsEnabled = false // prevent the control from being clickable | |
}; | |
StackCurve.Children.Add(thumb); | |
} | |
SliderSensitivityX.Value = ProfilesPage.selectedProfile.MotionSensivityX; | |
SliderSensitivityY.Value = ProfilesPage.selectedProfile.MotionSensivityY; | |
tb_ProfileAimingDownSightsMultiplier.Value = ProfilesPage.selectedProfile.AimingSightsMultiplier; | |
Toggle_FlickStick.IsOn = ProfilesPage.selectedProfile.FlickstickEnabled; | |
tb_ProfileFlickDuration.Value = ProfilesPage.selectedProfile.FlickstickDuration * 1000; | |
tb_ProfileStickSensitivity.Value = ProfilesPage.selectedProfile.FlickstickSensivity; | |
// todo: improve me ? | |
ProfilesPageHotkey.inputsChord.State = ProfilesPage.selectedProfile.AimingSightsTrigger.Clone() as ButtonState; | |
ProfilesPageHotkey.DrawInput(); | |
// temp | |
StackCurve.Children.Clear(); | |
foreach (KeyValuePair<double, double> elem in ProfilesPage.selectedProfile.MotionSensivityArray) | |
{ | |
// skip first item ? | |
if (elem.Key == 0) | |
continue; | |
double height = elem.Value * StackCurve.Height; | |
Thumb thumb = new Thumb | |
{ | |
Tag = elem.Key, | |
Width = 8, | |
MaxHeight = StackCurve.Height, | |
Height = height, | |
VerticalAlignment = VerticalAlignment.Bottom, | |
Background = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentLowBrush"], | |
BorderThickness = new Thickness(0), | |
BorderBrush = (Brush)Application.Current.Resources["SystemControlHighlightAltListAccentHighBrush"], | |
IsEnabled = false // prevent the control from being clickable | |
}; | |
StackCurve.Children.Add(thumb); | |
} | |
private void UpdateUIWithProfileSettings() | |
{ | |
SliderSensitivityX.Value = ProfilesPage.selectedProfile.MotionSensivityX; | |
// Add other UI updates here... | |
} | |
Application.Current.Dispatcher.Invoke(UpdateUIWithProfileSettings); |
private static object queryCacheValue(ManagementObjectCollection collection, string query, [CallerArgumentExpression("collection")] string collectionName = "") | ||
{ | ||
get | ||
if (!cache.ContainsKey($"{collectionName}-{query}")) | ||
{ | ||
if (!string.IsNullOrEmpty(_Manufacturer)) | ||
return _Manufacturer; | ||
|
||
foreach (ManagementObject queryObj in baseboardCollection) | ||
if (collection is not null) | ||
{ | ||
var query = queryObj["Manufacturer"]; | ||
if (query is not null) | ||
foreach (ManagementObject queryObj in collection) | ||
{ | ||
_Manufacturer = query.ToString(); | ||
break; | ||
object queryResult = queryObj[query]; | ||
if (queryResult is not null) | ||
{ | ||
cache.Add($"{collectionName}-{query}", queryResult); | ||
writeCache(); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
return _Manufacturer; | ||
} | ||
} | ||
|
||
public static string Model | ||
{ | ||
get | ||
{ | ||
foreach (ManagementObject queryObj in baseboardCollection) | ||
{ | ||
var query = queryObj["Model"]; | ||
if (query is not null) | ||
return query.ToString(); | ||
} | ||
|
||
return string.Empty; | ||
} | ||
if (cache.TryGetValue($"{collectionName}-{query}", out var result)) | ||
return result; | ||
|
||
return string.Empty; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The queryCacheValue
method efficiently handles caching by checking the cache before querying WMI and caching the results. This reduces redundant WMI queries and improves performance. However, consider handling exceptions that may occur during WMI querying to prevent application crashes.
+ try
+ {
+ foreach (ManagementObject queryObj in collection)
+ {
+ object queryResult = queryObj[query];
+ if (queryResult is not null)
+ {
+ cache.Add($"{collectionName}-{query}", queryResult);
+ writeCache();
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ // Log or handle the exception
+ }
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
private static object queryCacheValue(ManagementObjectCollection collection, string query, [CallerArgumentExpression("collection")] string collectionName = "") | |
{ | |
get | |
if (!cache.ContainsKey($"{collectionName}-{query}")) | |
{ | |
if (!string.IsNullOrEmpty(_Manufacturer)) | |
return _Manufacturer; | |
foreach (ManagementObject queryObj in baseboardCollection) | |
if (collection is not null) | |
{ | |
var query = queryObj["Manufacturer"]; | |
if (query is not null) | |
foreach (ManagementObject queryObj in collection) | |
{ | |
_Manufacturer = query.ToString(); | |
break; | |
object queryResult = queryObj[query]; | |
if (queryResult is not null) | |
{ | |
cache.Add($"{collectionName}-{query}", queryResult); | |
writeCache(); | |
break; | |
} | |
} | |
} | |
return _Manufacturer; | |
} | |
} | |
public static string Model | |
{ | |
get | |
{ | |
foreach (ManagementObject queryObj in baseboardCollection) | |
{ | |
var query = queryObj["Model"]; | |
if (query is not null) | |
return query.ToString(); | |
} | |
return string.Empty; | |
} | |
if (cache.TryGetValue($"{collectionName}-{query}", out var result)) | |
return result; | |
return string.Empty; | |
} | |
private static object queryCacheValue(ManagementObjectCollection collection, string query, [CallerArgumentExpression("collection")] string collectionName = "") | |
{ | |
if (!cache.ContainsKey($"{collectionName}-{query}")) | |
{ | |
if (collection is not null) | |
{ | |
try | |
{ | |
foreach (ManagementObject queryObj in collection) | |
{ | |
object queryResult = queryObj[query]; | |
if (queryResult is not null) | |
{ | |
cache.Add($"{collectionName}-{query}", queryResult); | |
writeCache(); | |
break; | |
} | |
} | |
} | |
catch (Exception ex) | |
{ | |
// Log or handle the exception | |
} | |
} | |
} | |
if (cache.TryGetValue($"{collectionName}-{query}", out var result)) | |
return result; | |
return string.Empty; | |
} |
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Documentation
Style