Adding more Aapiium operations to mobile device action#4184
Conversation
|
""" WalkthroughThis update introduces a broad set of enhancements for mobile device interaction within the Ginger automation framework. The changes expand the UI for mobile device actions by adding new input fields and descriptive text blocks, particularly supporting folder path specification. The backend logic is extended with new properties and numerous mobile device actions, including device management, app operations, input simulation, and connectivity toggles. The Appium driver is significantly upgraded to implement these actions, featuring detailed input validation, error handling, and robust iOS keyboard simulation. No existing public APIs are removed or changed in signature; all modifications are additive. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI (ActMobileDeviceEditPage)
participant Backend (ActMobileDevice)
participant Driver (GenericAppiumDriver)
User->>UI (ActMobileDeviceEditPage): Selects mobile device action (e.g., PushFileToDevice)
UI (ActMobileDeviceEditPage)->>UI (ActMobileDeviceEditPage): Displays relevant input fields and descriptive text
User->>UI (ActMobileDeviceEditPage): Enters input values and triggers action
UI (ActMobileDeviceEditPage)->>Backend (ActMobileDevice): Binds input values to action properties
Backend (ActMobileDevice)->>Driver (GenericAppiumDriver): Invokes corresponding method for action
Driver (GenericAppiumDriver)->>Driver (GenericAppiumDriver): Validates input, executes device operation, handles errors
Driver (GenericAppiumDriver)-->>Backend (ActMobileDevice): Returns result or status
Backend (ActMobileDevice)-->>UI (ActMobileDeviceEditPage): Updates UI with results or messages
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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 using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 9
🔭 Outside diff range comments (2)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (2)
1-35: 🛠️ Refactor suggestionDuplicate license header – remove the second block
Two identical
#region Licenseblocks appear back-to-back. This bloats the file and will trigger static-analysis “duplicate-text” warnings.-#region License -/* -Copyright … -*/ -#endregion -#region License +#region License /* Copyright … */ #endregion
3946-3963:⚠️ Potential issueREST helper leaks
RestClient– make it per-request
restClientis a field but every call toGetDeviceMetricOverAPIre-initialises it, overwriting any concurrent request.
Because the driver is used from parallel Ginger runners this causes race conditions.Instantiate a local
RestClientinside the method or guard access with a lock.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml(2 hunks)Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs(7 hunks)Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs(3 hunks)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs(21 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (2)
Ginger/GingerCoreCommon/Actions/Act.cs (1)
AddOrUpdateInputParamValue(824-847)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (22)
GrantAppPermission(5221-5251)TypeUsingIOSkeyboard(4634-4663)ClearAppdata(4680-4706)ScreenSize(4806-4820)OpenNotificationsPanel(4821-4838)GetDeviceTime(4839-4850)GetAppPackage(986-1030)GetCurrentActivityDetails(2119-2151)LockForDuration(4852-4886)GetSettings(4887-4914)PushFolder(4983-5006)ToggleLocationServices(5055-5071)ToggleData(5072-5096)ToggleAirplaneMode(5098-5122)ToggleWifi(5123-5146)IsIMEActive(5147-5161)GetIMEActiveEngine(5162-5176)StartActivity(5177-5194)GetGeoLocation(5195-5219)SendAppToBackground(5252-5275)SetNetworkConnection(5276-5294)GetDeviceOSType(4664-4679)
🔇 Additional comments (12)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml (2)
28-28: Good addition of a text block for showing contextual information.Adding
xInputTextBlockis a good enhancement for providing additional guidance to users, especially for platform-specific notes as seen later in the TypeUsingIOSkeyboard implementation.
100-104: Good implementation of the folder transfer panel.The new
xFolderTransferPnlproperly follows the UI pattern established in the file. The panel will support the newly added PushFolder operation, allowing users to specify device target folders separately from local folders.Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (8)
86-88: Correct initialization of the new folder path input control.The initialization of
xFolderPathTextBoxcorrectly sets up the control to handle folder browsing with appropriate context.
240-240: Appropriate visibility setup for the new folder transfer panel.Correctly hiding the folder transfer panel by default maintains consistency with how other panels are handled in the UI.
357-361: Well-implemented UI handling for iOS keyboard typing.Good implementation for the TypeUsingIOSkeyboard action with appropriate label and helpful note about Android limitations. The note about not combining single and double quotes will help users avoid common typing issues.
371-375: Good addition of time duration input for device lock.The implementation for LockForDuration properly configures the input field with a clear label indicating the time unit (seconds).
380-385: Appropriate UI configuration for granting app permissions.The GrantAppPermission case correctly shows both the app package panel and permission input field with a clear label.
386-392: Well-implemented UI for folder push operation.The PushFolder action correctly shows the folder transfer panel and hides unnecessary file path controls. The label "Local Folder to Push" clearly indicates the purpose of the input.
394-398: Good implementation of background app duration control.The SendAppToBackground case correctly configures the input field with an appropriate label that clearly indicates the time unit (seconds).
399-404: Appropriate UI setup for starting activities.The StartActivity case correctly shows both the app package panel and activity input field, which aligns with the Android-specific implementation in the driver.
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (2)
158-169: Good implementation of the LocalFolderPathInput property.The new property follows the same pattern as other input properties in the class, using proper get/set accessors and the established pattern for parameter creation and updates.
525-570: Excellent expansion of mobile device action capabilities.The addition of numerous new mobile device actions significantly enhances the framework's capabilities for mobile automation. The actions cover a broad range of device operations including:
- App management (ClearAppdata, GrantAppPermission, StartActivity)
- Device control (LockForDuration, ToggleLocationServices, ToggleData, etc.)
- Information retrieval (ScreenSize, GetDeviceTime, GetOrientation, etc.)
- File operations (PushFolder)
- Input simulation (TypeUsingIOSkeyboard)
All enum values have appropriate descriptive attributes, making them clear in the UI.
| [EnumValueDescription("Grant App Permission")] | ||
| GrantAppPermission, | ||
| [EnumValueDescription("Type Using keyboard")] | ||
| TypeUsingIOSkeyboard, | ||
| [EnumValueDescription("Clear App Data")] | ||
| ClearAppdata, | ||
| [EnumValueDescription("Get Screen Size")] | ||
| ScreenSize, | ||
| [EnumValueDescription("Open Notifications Panel")] | ||
| OpenNotificationsPanel, | ||
| [EnumValueDescription("Get Device Time")] | ||
| GetDeviceTime, | ||
| [EnumValueDescription("Get Orientation")] | ||
| GetOrientation, | ||
| [EnumValueDescription("Get App Package")] | ||
| GetAppPackage, | ||
| [EnumValueDescription("Get Current Activity Details")] | ||
| GetCurrentActivityDetails, | ||
| [EnumValueDescription("Lock For Time Duration")] | ||
| LockForDuration, | ||
| [EnumValueDescription("Get Settings")] | ||
| GetSettings, | ||
| [EnumValueDescription("Push Folder to Device")] | ||
| PushFolder, | ||
| [EnumValueDescription("Toggle Location Services")] | ||
| ToggleLocationServices, | ||
| [EnumValueDescription("Toggle Data")] | ||
| ToggleData, | ||
| [EnumValueDescription("Toggle Airplane Mode")] | ||
| ToggleAirplaneMode, | ||
| [EnumValueDescription("Toggle Wifi")] | ||
| ToggleWifi, | ||
| [EnumValueDescription("Is IME Active")] | ||
| IsIMEActive, | ||
| [EnumValueDescription("Get IME Active Engine")] | ||
| GetIMEActiveEngine, | ||
| [EnumValueDescription("Start Activity")] | ||
| StartActivity, | ||
| [EnumValueDescription("Get GeoLocation")] | ||
| GetGeoLocation, | ||
| [EnumValueDescription("Send App to Background")] | ||
| SendAppToBackground, | ||
| [EnumValueDescription("Set Network Connection")] | ||
| SetNetworkConnection, | ||
| [EnumValueDescription("Get Device OS Type")] | ||
| GetDeviceOSType, |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Consider adding enum value grouping or categorization.
With the significant expansion of mobile device actions (now over 45 operations), it might be beneficial to organize these enum values into logical categories, either through comments, regions, or a nested enum approach. This would improve maintainability as the list continues to grow.
For example, you could add region directives to group related actions:
public enum eMobileDeviceAction
{
+ #region Touch Interaction
[EnumValueDescription("Press XY")]
PressXY,
// other touch-related actions...
+ #endregion
+ #region Device Controls
[EnumValueDescription("Press Back Button")]
PressBackButton,
// other device control actions...
+ #endregion
+ #region App Management
[EnumValueDescription("Open App")]
OpenApp,
// other app management actions...
+ #endregion
// etc.
}Committable suggestion skipped: line range outside the PR's diff.
| [EnumValueDescription("Type Using keyboard")] | ||
| TypeUsingIOSkeyboard, |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Clarify iOS-specific keyboard action in enum description.
The description "Type Using keyboard" doesn't clearly indicate that this is primarily for iOS keyboard simulation (as shown in the implementation and UI note). Consider updating the description to be more specific.
- [EnumValueDescription("Type Using keyboard")]
+ [EnumValueDescription("Type Using iOS keyboard")]
TypeUsingIOSkeyboard,| using System.Threading; | ||
| using System.Threading.Tasks; |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Thread.Sleep calls in UI test code block the STA thread
Blocking the agent thread with Thread.Sleep (e.g. LockForDuration) prevents Ginger from processing cancellation requests and UI events.
Prefer asynchronous waits:
await Task.Delay(milliseconds, cancellationToken);or Appium’s built-in Wait utilities.
| using GingerCoreNET.SolutionRepositoryLib.RepositoryObjectsLib.PlatformsLib; | ||
| using Newtonsoft.Json; | ||
| using Newtonsoft.Json.Linq; | ||
| using NUglify.Html; |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Unused using directive adds unnecessary dependency
using NUglify.Html; is not referenced anywhere in the file. Keeping it:
- increases compile time,
- introduces an avoidable third-party dependency, and
- will raise “unused import” warnings.
Remove the directive unless you plan to minify HTML in this class.
There was a problem hiding this comment.
🧩 Analysis chain
I need to verify this claim about IsAlphaUpper() being from NUglify.Html.
The script execution results will help me understand if the import is actually needed for this method.
🏁 Script executed:
# Look for IsAlphaUpper method and its usage
rg -A 2 -B 2 "IsAlphaUpper"
Length of output: 766
🏁 Script executed:
# Look for the definition of IsAlphaUpper method
rg "public static bool IsAlphaUpper" --include="*.cs"
# Also check if there are any other IsAlphaUpper methods in the codebase
rg "IsAlphaUpper.*\(" --include="*.cs"
# Check for any reference to NUglify.Html in the context of IsAlphaUpper
rg "NUglify.Html.*IsAlphaUpper" -A 5 -B 5 --include="*.cs"
# Check if IsAlphaUpper is an extension method defined in the file
rg "static.*IsAlphaUpper.*\(this char" --include="*.cs"
Length of output: 1983
🏁 Script executed:
# Look for the definition of IsAlphaUpper method
rg "public static bool IsAlphaUpper" -t cs
# Also check if there are any other IsAlphaUpper methods in the codebase
rg "IsAlphaUpper.*\(" -t cs
# Check for any reference to NUglify.Html in the context of IsAlphaUpper
rg "NUglify.Html.*IsAlphaUpper" -A 5 -B 5 -t cs
# Check if IsAlphaUpper is an extension method defined in the file
rg "static.*IsAlphaUpper.*\(this char" -t cs
# Check if the NUglify.Html namespace contains an IsAlphaUpper method
rg -A 5 -B 5 "namespace NUglify.Html" -t cs
Length of output: 387
@shai1712 I've checked the codebase, and I couldn't find any evidence that the IsAlphaUpper() method comes from the NUglify.Html namespace. The searches for its definition or any connection to NUglify didn't return any results.
NUglify is primarily used for HTML/CSS/JS minification rather than providing character manipulation utilities. The IsAlphaUpper() method is likely either:
- Defined elsewhere in your codebase as an extension method
- Coming from another library entirely
If you're certain this method is needed, could you help locate where IsAlphaUpper() is defined? That would help determine which import is actually required for it.
🧬 Code Graph Analysis Results
Relevant snippet from Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (lines 1720-1800 approx, extracted and summarized)
public void TypeUsingIOSkeyboard(string text)
{
if (string.IsNullOrEmpty(text))
{
throw new ArgumentException("Text cannot be null or empty", nameof(text));
}
try
{
if (Driver is IOSDriver)
{
foreach (char c in text)
{
SelectSubKeyboard(c);
}
}
else if (Driver is AndroidDriver)
{
((AndroidDriver)Driver).ExecuteScript("mobile: type", new Dictionary<string, object>{{ "text", text }});
}
else
{
throw new NotSupportedException($"Driver type is not supported for keyboard typing");
}
}
catch (Exception ex)
{
throw new($"An error occurred while typing text: {ex.Message}");
}
}
public void SelectSubKeyboard(char c)
{
char[] FirstSpecialCharacters = ['-', '/', ':', ';', '(', ')', '$', '&', '@', '"', '\''];
char[] SecondSpecialCharacters = { '|', '~', '<', '>', '^', '+', '=', '¥', '£', '€' };
if (c == ' ')
{
ChosenKey(c.ToString());
}
else if (char.IsDigit(c) || Array.Exists(FirstSpecialCharacters, element => element == c))
{
switchToNumbersOrSymbols();
ChosenKey(c.ToString());
switchToLetters(c);
}
else if (char.IsPunctuation(c) || Array.Exists(SecondSpecialCharacters, element => element == c))
{
switchToNumbersOrSymbols();
switchToSpecialKey();
ChosenKey(c.ToString());
switchToLetters(c);
}
else if (Char.IsLetter(c))
{
switchToCapitalLetter(c);
ChosenKey(c.ToString());
}
}
public void switchToNumbersOrSymbols()
{
var numbersKey = ((IOSDriver)Driver).FindElement(By.XPath("//XCUIElementTypeKey[@name='123' or @label='numbers']"));
bool isNumbersActive = numbersKey.GetAttribute("enabled") == "true";
if (isNumbersActive)
{
numbersKey.Click();
}
}
public void switchToLetters(char c)
{
if (c != '\'')
{
((IOSDriver)Driver).FindElement(By.XPath("//XCUIElementTypeKey[@name='more' or @label='ABC']")).Click();
}
}
public void switchToSpecialKey()
{
var specialKey = ((IOSDriver)Driver).FindElement(By.XPath("//XCUIElementTypeButton[@name='shift' or @label='symbols']"));
bool isSpecialActive = specialKey.GetAttribute("enabled") == "true";
if (isSpecialActive)
{
specialKey.Click();
}
}
public void switchToCapitalLetter(char c)
{
var shiftKey = ((IOSDriver)Driver).FindElement(By.XPath("//*[contains(@label,'shift') or contains(@value,'shift')]"));
bool isShiftActive = shiftKey.GetAttribute("selected") == "true";
if ((c.IsAlphaUpper() && !isShiftActive) || (Char.IsLower(c) && isShiftActive))
{
shiftKey.Click();
}
}
public void ChosenKey(string charToFind)
{
var specialChars = new Dictionary<string, string>
{
{ "\'", "\'" }, // Single quote
{ "\"", "\"" }, // Double quote
{ "&", "ampersand" }, // Ampersand
{" ", "space" }, // Space
};
string searchValue;
if (specialChars.TryGetValue(charToFind, out searchValue))
{
searchValue = specialChars[charToFind];
}
else
{
searchValue = charToFind;
}
string xpath = char.Parse(charToFind) == '\'' ?
$"//*[@name=\"{searchValue}\" or @label=\"{searchValue}\" or @value=\"{searchValue}\" or @hint=\"{searchValue}\" or @content-desc=\"{searchValue}\"]"
:$"//*[@name='{searchValue}' or @label='{searchValue}' or @value='{searchValue}' or @hint='{searchValue}' or @content-desc='{searchValue}']";
((IOSDriver)Driver).FindElements(By.XPath(xpath))[0].Click();
}Summary:
TypeUsingIOSkeyboard(string text): Types the given text on the iOS keyboard by iterating over each character and selecting the appropriate sub-keyboard and key.SelectSubKeyboard(char c): Determines which sub-keyboard to switch to based on the character (letters, digits, punctuation, special characters, space).switchToNumbersOrSymbols(): Switches to the numbers/symbols keyboard if not already active.switchToLetters(char c): Switches back to letters keyboard unless the character is a single quote.switchToSpecialKey(): Switches to the secondary symbols keyboard (#+=).switchToCapitalLetter(char c): Toggles the shift key based on whether the character is uppercase or lowercase.ChosenKey(string charToFind): Finds the key element on the iOS keyboard by XPath and clicks it. Handles special characters with a mapping.
Relevant snippet from Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (lines 1700-1720 approx)
public static class CharExtensions
{
public static bool IsAlphaUpper(this char c)
{
return char.IsLetter(c) && char.IsUpper(c);
}
}Summary:
- Extension method
IsAlphaUpper()forchartype to check if a character is an uppercase alphabetic letter.
Relevant snippet from Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (lines 30-668)
- Defines the enum
eMobileDeviceActionwhich includesTypeUsingkeyboardas one of the actions. ActMobileDeviceclass has a propertyMobileDeviceActionof typeeMobileDeviceAction.- This class is used in
GenericAppiumDriverto handle mobile device actions includingTypeUsingkeyboard.
Relevant snippet from Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (lines 1100-1300 approx)
- Method
MobileDeviceActionHandler(ActMobileDevice act)handles various mobile device actions. - For the action
TypeUsingkeyboard, it callsTypeUsingIOSkeyboard(act.ActionInput.ValueForDriver); TypeUsingIOSkeyboardis the method that uses theIsAlphaUpper()extension method and the sub-keyboard switching logic.
Summary of relevance to user comment:
The user comment is about the usage of IsAlphaUpper() method in the TypeUsingIOSkeyboard operation. The relevant code is the TypeUsingIOSkeyboard method and its helper methods (SelectSubKeyboard, switchToNumbersOrSymbols, switchToLetters, switchToSpecialKey, switchToCapitalLetter, ChosenKey) in GenericAppiumDriver.cs. Also relevant is the IsAlphaUpper() extension method for char which is used in switchToCapitalLetter to determine if the character is uppercase alphabetic.
These snippets provide the full context of how IsAlphaUpper() is used in the typing operation on iOS keyboard in the mobile driver.
| public void TypeUsingIOSkeyboard(string text) | ||
| { | ||
| if (Driver is AndroidDriver) | ||
| if (string.IsNullOrEmpty(text)) | ||
| { | ||
| ((AndroidDriver)Driver).InstallApp(appPath); | ||
| throw new ArgumentException("Text cannot be null or empty", nameof(text)); | ||
| } | ||
| else if (Driver is IOSDriver) | ||
| try | ||
| { | ||
| ((IOSDriver)Driver).InstallApp(appPath); | ||
| if (Driver is IOSDriver) | ||
| { | ||
| foreach (char c in text) | ||
| { | ||
| SelectSubKeyboard(c); | ||
| } | ||
| } | ||
| else if (Driver is AndroidDriver) | ||
| { | ||
| //string escapedText = text.Replace("'", "\'").Replace("\"", "\""); | ||
| ((AndroidDriver)Driver).ExecuteScript("mobile: type", new Dictionary<string, object>{{ "text", text }}); | ||
| } | ||
| else | ||
| { | ||
| throw new NotSupportedException($"Driver type '{Driver.GetType().Name}' is not supported for keyboard typing"); | ||
| } | ||
| } | ||
| else | ||
| catch (Exception ex) | ||
| { | ||
| throw new InvalidOperationException("Unsupported driver type"); | ||
| throw new($"An error occurred while typing text: {ex.Message}"); | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
TypeUsingIOSkeyboard – compile-time error & heavy XPath usage
-
c.IsAlphaUpper()is not a BCL method forchar; unless you added an extension elsewhere this will not compile.
Replace withchar.IsUpper(c). -
For every character the code hits the DOM with
FindElements(By.XPath(...))[0].
On iOS that is extremely slow (dozens of round-trips for long strings).
Recommendations:
- Fix the compilation error.
- Cache frequently-used elements (shift, numbers etc.).
- Build an
ActionSequenceor call Appium’smobile:typeendpoint instead of per-char XPath.
| public void PushFolder(string localFolderPath, string remoteFolderPath) // working for android, for ios need to see the files via itunes | ||
| //Appium currently doesn't directly support pushing an entire folder in one go. Instead, you can push all the files and recreate the folder structure on the device programmatically. | ||
| { | ||
| if (!Directory.Exists(localFolderPath)) | ||
| { | ||
| throw new DirectoryNotFoundException($"Local Folder not found: {localFolderPath}"); | ||
| } | ||
| if (string.IsNullOrEmpty(remoteFolderPath)) | ||
| { | ||
| throw new ArgumentException("Device Target Folder path cannot be null or empty", nameof(remoteFolderPath)); | ||
| } | ||
| foreach (var filePath in Directory.GetFiles(localFolderPath)) | ||
| { | ||
| var remoteFilePath = remoteFolderPath + Path.GetFileName(filePath); | ||
| try | ||
| { | ||
| Driver.PushFile(remoteFilePath, new FileInfo(filePath)); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| throw new($"Failed to push file {filePath}: {ex.Message}"); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
PushFolder – path concatenation will break on most OSes
remoteFilePath = remoteFolderPath + Path.GetFileName(filePath);
- If
remoteFolderPathdoes not end with a separator the resulting path is invalid (…/folderfile.txt). - On Android a missing “/” silently pushes to the parent directory.
Use Path.Combine (for local) and string interpolation with a guaranteed “/” for device paths.
-var remoteFilePath = remoteFolderPath + Path.GetFileName(filePath);
+var remoteFilePath = $"{remoteFolderPath.TrimEnd('/')}/{Path.GetFileName(filePath)}";| public string SetFilePath(string FileType, string FilePath, string FileName) | ||
| { | ||
| string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); | ||
| string fileName = Path.GetFileName(FilePath); | ||
| string targetFile = string.IsNullOrEmpty(fileName) ? Path.Combine(FilePath, $"{FileName}_{timestamp}.{FileType}") : $"{FilePath}.{FileType}"; | ||
| return targetFile; | ||
| { | ||
| if (!string.IsNullOrEmpty(FilePath) && Directory.Exists(FilePath)) | ||
| { | ||
| string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); | ||
| string fileName = Path.GetFileName(FilePath); | ||
| string targetFile = string.IsNullOrEmpty(fileName) ? Path.Combine(FilePath, $"{FileName}_{timestamp}.{FileType}") : $"{FilePath}.{FileType}"; | ||
| return targetFile; | ||
| } | ||
| else | ||
| { | ||
| throw new($"An error occurred while running script: Got invalid Directory or empty folder"); | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
SetFilePath ‑ parameter shadowing & faulty target-file logic
Issues:
- Local variable
fileNameshadows theFileNameparameter → very confusing. - When
fileNamedoes exist the path becomes"{FilePath}.{FileType}", dropping the original file name and probably duplicating the extension. - No path separator is inserted when the caller forgets to supply a trailing slash.
-public string SetFilePath(string FileType, string FilePath, string FileName)
+public string SetFilePath(string fileType, string directory, string baseName)
{
- if (!string.IsNullOrEmpty(FilePath) && Directory.Exists(FilePath))
+ if (!Directory.Exists(directory))
+ throw new DirectoryNotFoundException($"Directory '{directory}' does not exist");
+
+ // normalise input
+ baseName ??= "file";
+
+ string timeStamp = DateTime.Now:yyyyMMddHHmmss;
+ string targetName = $"{baseName}_{timeStamp}.{fileType.TrimStart('.')}";
+ return Path.Combine(directory, targetName);
}This:
- removes the shadowing,
- always preserves the caller-supplied filename,
- prevents malformed paths, and
- uses
Path.Combineto stay cross-platform.
Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Actionable comments posted: 4
🔭 Outside diff range comments (1)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (1)
224-406: 🧹 Nitpick (assertive)Consider refactoring the SetControlsView method for better maintainability.
The
SetControlsViewmethod is getting large with numerous switch cases (now more than 20). As more mobile actions are added, this method will become difficult to maintain.Consider extracting each case or group of related cases into separate methods:
private void SetControlsView() { ResetAllPanelsVisibility(); switch (mAct.MobileDeviceAction) { case ActMobileDevice.eMobileDeviceAction.PressKey: case ActMobileDevice.eMobileDeviceAction.LongPressKey: ConfigureKeyPressView(); break; // Other cases... case ActMobileDevice.eMobileDeviceAction.StartActivity: ConfigureStartActivityView(); break; } } private void ResetAllPanelsVisibility() { xKeyPressPnl.Visibility = Visibility.Collapsed; xXY1Pnl.Visibility = Visibility.Collapsed; // Reset all other panels... } private void ConfigureKeyPressView() { xKeyPressPnl.Visibility = Visibility.Visible; } private void ConfigureStartActivityView() { xAppPnl.Visibility = Visibility.Visible; xInputLabelVE.Content = "Activity:"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs(7 hunks)
🔇 Additional comments (4)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (4)
240-240: LGTM - Added visibility control for the new folder transfer panel.
358-362: Good implementation of iOS keyboard typing support.The code correctly sets up the UI for the new
TypeUsingIOSkeyboardaction with an appropriate note about Android limitations.
387-393: Good implementation of folder push functionality.The UI configuration for the new
PushFolderaction correctly sets up the necessary controls and visibility.
303-303: LGTM - Added support for clearing app data.
| xFolderPathTxtBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); | ||
|
|
||
| xFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.LocalFolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Consider clearer naming convention for folder path controls.
The naming of xFolderPathTxtBox and xFolderPathTextBox is too similar and could lead to confusion during maintenance. These controls appear to have different purposes (device folder path vs local folder path).
-xFolderPathTxtBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*");
-
-xFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.LocalFolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*");
+xDeviceFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*");
+
+xLocalFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.LocalFolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*");📝 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. Thoroughly test & benchmark the code to ensure it meets the requirements.
| xFolderPathTxtBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); | |
| xFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.LocalFolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); | |
| xDeviceFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); | |
| xLocalFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.LocalFolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); |
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (12)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (6)
28-28: Unused imports detected.The imports
System.Drawing.Drawing2DandSystem.Linqappear to be unused in this class. Consider removing them to keep the code clean and reduce unnecessary dependencies.-using System.Drawing.Drawing2D; -using System.Linq;Also applies to: 30-30
86-88: Consider clearer naming convention for folder path controls.The naming of
xFolderPathTxtBoxandxFolderPathTextBoxis too similar and could lead to confusion during maintenance. These controls appear to have different purposes (device folder path vs local folder path).-xFolderPathTxtBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); - -xFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.LocalFolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); +xDeviceFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); + +xLocalFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.LocalFolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*");
375-379: Add input validation for time duration inputs.For
LockForDurationaction that requires time in seconds, there's no validation to ensure users enter numeric values or reasonable durations. Consider adding validation to prevent runtime errors.case ActMobileDevice.eMobileDeviceAction.LockForDuration: xInputLabelVE.Content = "Set a Time Duration for Lock(Seconds):"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; + // Add validation for numeric input in seconds + xInputVE.ValueTextBox.PreviewTextInput += (s, e) => + { + e.Handled = !char.IsDigit(e.Text[0]) && !char.IsPunctuation(e.Text[0]); + }; break;
384-389: Consider adding documentation for the new actions.The new action
GrantAppPermissionis added without comments explaining its purpose or expected inputs. Adding XML documentation would improve maintainability.+/// <summary> +/// Configures UI for granting app permissions +/// </summary> case ActMobileDevice.eMobileDeviceAction.GrantAppPermission: xAppPnl.Visibility = Visibility.Visible; xInputLabelVE.Content = "Permission:"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; break;
399-404: Add input validation for time duration inputs.For
SendAppToBackgroundaction that requires time in seconds, there's no validation to ensure users enter numeric values or reasonable durations. Consider adding validation to prevent runtime errors.case ActMobileDevice.eMobileDeviceAction.SendAppToBackground: xInputLabelVE.Content = "Set a Time Duration for Backgroud(Seconds):"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; + // Add validation for numeric input in seconds + xInputVE.ValueTextBox.PreviewTextInput += (s, e) => + { + e.Handled = !char.IsDigit(e.Text[0]) && !char.IsPunctuation(e.Text[0]); + }; break;
405-409: Consider adding documentation for the new actions.The new action
StartActivityis added without comments explaining its purpose or expected inputs. Adding XML documentation would improve maintainability.+/// <summary> +/// Configures UI for starting a specific activity within an application +/// </summary> case ActMobileDevice.eMobileDeviceAction.StartActivity: xAppPnl.Visibility = Visibility.Visible; xInputLabelVE.Content = "Activity:"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; break;Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (1)
527-528: Clarify iOS-specific keyboard action in enum description.The description "Type Using keyboard" doesn't clearly indicate that this is primarily for iOS keyboard simulation (as shown in the implementation and UI note). Consider updating the description to be more specific.
- [EnumValueDescription("Type Using keyboard")] + [EnumValueDescription("Type Using iOS keyboard")] TypeUsingIOSkeyboard,Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (5)
55-55:NUglify.Htmldirective is still unused – please drop itIdentical feedback was provided in an earlier review; the directive remains and is still unused.
Safe to delete.
4127-4139:SetFilePathstill suffers from shadowing, path bugs & throws compilation errorsIssues (unchanged from the previous review):
- Local
fileNameshadows the parameterFileName.- When
fileNameexists the returned path becomes"{FilePath}.{FileType}", losing the original file name and duplicating the extension.- No path separator is inserted when the caller forgets a trailing slash.
- Uses the invalid
throw new($"…")syntax flagged above.Suggested minimal, compilable fix:
-public string SetFilePath(string FileType, string FilePath, string FileName) +public string SetFilePath(string fileType, string directory, string baseName) { - if (!string.IsNullOrEmpty(FilePath) && Directory.Exists(FilePath)) + if (!Directory.Exists(directory)) + throw new DirectoryNotFoundException($"Directory '{directory}' does not exist"); + + // Normalise input + baseName ??= "file"; + + string timeStamp = DateTime.Now.ToString("yyyyMMddHHmmss"); + string targetName = $"{baseName}_{timeStamp}.{fileType.TrimStart('.')}"; + return Path.Combine(directory, targetName); - … - throw new($"An error occurred while running script: Got invalid Directory or empty folder"); }
4583-4587:IsAlphaUpper()still undefined – compile-time error
c.IsAlphaUpper()is not a BCL method, nor is an extension defined in this file/namespace.
Compilation will fail unless an extension exists elsewhere.
Replace with the standardchar.IsUpper(c)(or define the extension).
4990-4999:PushFolderpath concatenation is still fragilevar remoteFilePath = remoteFolderPath + Path.GetFileName(filePath);If
remoteFolderPathlacks a trailing “/”, the resulting path is invalid (…/folderfile.txt).
Use a safe join that guarantees exactly one slash:-var remoteFilePath = remoteFolderPath + Path.GetFileName(filePath); +var remoteFilePath = $"{remoteFolderPath.TrimEnd('/')}/{Path.GetFileName(filePath)}";
4865-4876: 🧹 Nitpick (assertive)Blocking the driver thread with
Thread.Sleephampers responsiveness
Thread.Sleep(…)inLockForDurationblocks the STA thread, preventing:
- event pumping,
- cancellation requests,
- UI refreshes.
Prefer asynchronous waits or driver-native wait APIs, e.g.:
await Task.Delay(TimeSpan.FromSeconds(seconds), token);Or, on Android, poll
Driver.IsLocked()in a loop with short delays.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml(2 hunks)Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs(7 hunks)Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs(3 hunks)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs(12 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (2)
Ginger/GingerCoreCommon/Actions/Act.cs (1)
AddOrUpdateInputParamValue(825-848)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (21)
GrantAppPermission(5217-5247)TypeUsingIOSkeyboard(4629-4658)ClearAppdata(4675-4701)ScreenSize(4801-4815)OpenNotificationsPanel(4816-4833)GetDeviceTime(4834-4845)GetAppPackage(987-1031)GetCurrentActivityDetails(2120-2152)LockForDuration(4847-4881)GetSettings(4882-4909)ToggleLocationServices(5051-5067)ToggleData(5068-5092)ToggleAirplaneMode(5094-5118)ToggleWifi(5119-5142)IsIMEActive(5143-5157)GetIMEActiveEngine(5158-5172)StartActivity(5173-5190)GetGeoLocation(5191-5215)SendAppToBackground(5248-5271)SetNetworkConnection(5272-5290)GetDeviceOSType(4659-4674)
🔇 Additional comments (1)
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (1)
158-169: Good implementation of the LocalFolderPathInput property.The new property follows the established pattern for handling input values in this class.
| <Actions:UCValueExpression x:Name="xFilePathTextBox" HorizontalAlignment="Left" Margin="0,0,0,0" Width="335"/> | ||
| <Label x:Name="xFolderPathLbl" Style="{StaticResource $LabelStyle}" Content="Local Target Folder:" Margin="-3,0,0,0"/> | ||
| <Actions:UCValueExpression x:Name="xFolderPathTxtBox" Width="340" /> | ||
| <Actions:UCValueExpression x:Name="xFolderPathTxtBox" Width="335" /> | ||
| <TextBlock x:Name="xFolderTextBlock" Style="{StaticResource $TextBlockStyle}" FontSize="10" TextWrapping="Wrap" Width="330" Text="Target Folders Path: Documents: /storage/emulated/0/Documents/ Pictures: /storage/emulated/0/Pictures/ Downloads: /storage/emulated/0/Download/"/> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Inconsistent control widths.
The width of controls in this panel varies between 330px and 335px. Consider standardizing widths for better visual consistency.
-<Actions:UCValueExpression x:Name="xFilePathTextBox" HorizontalAlignment="Left" Margin="0,0,0,0" Width="335"/>
+<Actions:UCValueExpression x:Name="xFilePathTextBox" HorizontalAlignment="Left" Width="330"/>
<Label x:Name="xFolderPathLbl" Style="{StaticResource $LabelStyle}" Content="Local Target Folder:" Margin="-3,0,0,0"/>
-<Actions:UCValueExpression x:Name="xFolderPathTxtBox" Width="335" />
+<Actions:UCValueExpression x:Name="xFolderPathTxtBox" Width="330" />| <StackPanel x:Name="xFolderTransferPnl" HorizontalAlignment="Left" Orientation="Vertical" DockPanel.Dock="Top" Margin="5,10,0,0" Visibility="Collapsed"> | ||
| <Label x:Name="xLocalFolderPathLbl" Style="{StaticResource $LabelStyle}" Content="Device Target Folder:" Margin="-4,0,0,0"/> | ||
| <Actions:UCValueExpression x:Name="xFolderPathTextBox" HorizontalAlignment="Left" Margin="0,0,0,0" Width="330"/> | ||
|
|
||
| </StackPanel> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Remove redundant margin attributes and empty line.
The margin attribute with value "0,0,0,0" is redundant and there's an unnecessary empty line at the end of the StackPanel.
<StackPanel x:Name="xFolderTransferPnl" HorizontalAlignment="Left" Orientation="Vertical" DockPanel.Dock="Top" Margin="5,10,0,0" Visibility="Collapsed">
<Label x:Name="xLocalFolderPathLbl" Style="{StaticResource $LabelStyle}" Content="Device Target Folder:" Margin="-4,0,0,0"/>
- <Actions:UCValueExpression x:Name="xFolderPathTextBox" HorizontalAlignment="Left" Margin="0,0,0,0" Width="330"/>
+ <Actions:UCValueExpression x:Name="xFolderPathTextBox" HorizontalAlignment="Left" Width="330"/>
-
</StackPanel>📝 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. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <StackPanel x:Name="xFolderTransferPnl" HorizontalAlignment="Left" Orientation="Vertical" DockPanel.Dock="Top" Margin="5,10,0,0" Visibility="Collapsed"> | |
| <Label x:Name="xLocalFolderPathLbl" Style="{StaticResource $LabelStyle}" Content="Device Target Folder:" Margin="-4,0,0,0"/> | |
| <Actions:UCValueExpression x:Name="xFolderPathTextBox" HorizontalAlignment="Left" Margin="0,0,0,0" Width="330"/> | |
| </StackPanel> | |
| <StackPanel x:Name="xFolderTransferPnl" HorizontalAlignment="Left" Orientation="Vertical" DockPanel.Dock="Top" Margin="5,10,0,0" Visibility="Collapsed"> | |
| <Label x:Name="xLocalFolderPathLbl" Style="{StaticResource $LabelStyle}" Content="Device Target Folder:" Margin="-4,0,0,0"/> | |
| <Actions:UCValueExpression x:Name="xFolderPathTextBox" HorizontalAlignment="Left" Width="330"/> | |
| </StackPanel> |
| [EnumValueDescription("Grant App Permission")] | ||
| GrantAppPermission, | ||
| [EnumValueDescription("Type Using keyboard")] | ||
| TypeUsingIOSkeyboard, | ||
| [EnumValueDescription("Clear App Data")] | ||
| ClearAppdata, | ||
| [EnumValueDescription("Get Screen Size")] | ||
| ScreenSize, | ||
| [EnumValueDescription("Open Notifications Panel")] | ||
| OpenNotificationsPanel, | ||
| [EnumValueDescription("Get Device Time")] | ||
| GetDeviceTime, | ||
| [EnumValueDescription("Get Orientation")] | ||
| GetOrientation, | ||
| [EnumValueDescription("Get App Package")] | ||
| GetAppPackage, | ||
| [EnumValueDescription("Get Current Activity Details")] | ||
| GetCurrentActivityDetails, | ||
| [EnumValueDescription("Lock for Duration")] | ||
| LockForDuration, | ||
| [EnumValueDescription("Get Settings")] | ||
| GetSettings, | ||
| //[EnumValueDescription("Push Folder to Device")] | ||
| //PushFolder, | ||
| [EnumValueDescription("Toggle Location Services")] | ||
| ToggleLocationServices, | ||
| [EnumValueDescription("Toggle Data")] | ||
| ToggleData, | ||
| [EnumValueDescription("Toggle Airplane Mode")] | ||
| ToggleAirplaneMode, | ||
| [EnumValueDescription("Toggle Wifi")] | ||
| ToggleWifi, | ||
| [EnumValueDescription("Is IME Active")] | ||
| IsIMEActive, | ||
| [EnumValueDescription("Get IME Active Engine")] | ||
| GetIMEActiveEngine, | ||
| [EnumValueDescription("Start Activity")] | ||
| StartActivity, | ||
| [EnumValueDescription("Get GeoLocation")] | ||
| GetGeoLocation, | ||
| [EnumValueDescription("Send App to Background")] | ||
| SendAppToBackground, | ||
| [EnumValueDescription("Set Network Connection")] | ||
| SetNetworkConnection, | ||
| [EnumValueDescription("Get Device OS Type")] | ||
| GetDeviceOSType, | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Consider organizing enum values into logical groups.
With the significant addition of new actions, the enum now has over 45 operations which makes it harder to navigate and understand. Consider organizing these values into logical categories using region directives or comments.
For example:
public enum eMobileDeviceAction
{
#region Touch Interactions
[EnumValueDescription("Press XY")]
PressXY,
// other touch-related actions...
#endregion
#region App Management
[EnumValueDescription("Open App")]
OpenApp,
// other app management actions...
#endregion
#region Device Controls
[EnumValueDescription("Toggle Wifi")]
ToggleWifi,
// other device control actions...
#endregion
}
MeniKadosh1
left a comment
There was a problem hiding this comment.
See comments for changes and many many cleanups to do.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (19)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml (3)
95-96: 🧹 Nitpick (assertive)Inconsistent control widths.
The width of controls in this panel varies between 330px and 335px. Consider standardizing widths for better visual consistency.
-<Actions:UCValueExpression x:Name="xFilePathTextBox" HorizontalAlignment="Left" Margin="0,0,0,0" Width="335"/> +<Actions:UCValueExpression x:Name="xFilePathTextBox" HorizontalAlignment="Left" Width="330"/>
101-101: 🧹 Nitpick (assertive)Remove redundant empty line.
There's an unnecessary empty line at the end of this section.
98-99: 🧹 Nitpick (assertive)Inconsistent control width and helpful path information added.
The width inconsistency continues here, but the added TextBlock with predefined target folder paths provides valuable information to the user.
-<Actions:UCValueExpression x:Name="xFolderPathTxtBox" Width="335" /> +<Actions:UCValueExpression x:Name="xFolderPathTxtBox" Width="330" />Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (6)
84-84: Verify if folder controls are still needed.Previous review comments questioned whether folder controls are still necessary. Please confirm if this control initialization is still required.
358-362: 🛠️ Refactor suggestionAdd validation for iOS-specific typing action.
The TypeUsingIOSkeyboard action is primarily targeted at iOS devices as indicated by the note in the UI. Consider adding a runtime check to validate if the device is iOS before attempting to execute.
case ActMobileDevice.eMobileDeviceAction.TypeUsingIOSkeyboard: xInputLabelVE.Content = "Text:"; xInputTextBlock.Text = "Note: For IOS, Keyboard Should be Open."; + // Add warning message for Android devices + if (mContext?.RunsetExecutor?.CurrentActivity?.CurrentDriver?.IsDriverTypeAppiumAndroid == true) + { + xInputTextBlock.Text = "WARNING: This action is optimized for iOS. For Android, consider using standard input methods."; + } xInputPnl.Visibility = Visibility.Visible; break;
372-376: 🛠️ Refactor suggestionAdd input validation for time duration inputs.
For LockForDuration action that require time in seconds, there's no validation to ensure users enter numeric values or reasonable durations. Consider adding validation to prevent runtime errors.
case ActMobileDevice.eMobileDeviceAction.LockForDuration: xInputLabelVE.Content = "Set a Time Duration for Lock(Seconds):"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; + // Add validation for numeric input in seconds + xInputVE.ValueTextBox.PreviewTextInput += (s, e) => + { + e.Handled = !char.IsDigit(e.Text[0]) && !char.IsPunctuation(e.Text[0]); + }; break;
381-386: 🧹 Nitpick (assertive)Consider adding documentation for the new actions.
The new action GrantAppPermission is added without comments explaining its purpose or expected inputs. Adding XML documentation would improve maintainability.
+/// <summary> +/// Configures UI for granting app permissions +/// </summary> case ActMobileDevice.eMobileDeviceAction.GrantAppPermission: xAppPnl.Visibility = Visibility.Visible; xInputLabelVE.Content = "Permission:"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; break;
387-392: 🛠️ Refactor suggestionAdd input validation for SendAppToBackground duration.
Similar to LockForDuration, this action requires numeric time in seconds but has no validation to ensure valid input.
case ActMobileDevice.eMobileDeviceAction.SendAppToBackground: xInputLabelVE.Content = "Set a Time Duration for Backgroud(Seconds):"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; + // Add validation for numeric input in seconds + xInputVE.ValueTextBox.PreviewTextInput += (s, e) => + { + e.Handled = !char.IsDigit(e.Text[0]) && !char.IsPunctuation(e.Text[0]); + }; break;
393-399: 🧹 Nitpick (assertive)Add documentation for StartActivity action.
Similar to other new actions, StartActivity would benefit from XML documentation explaining its purpose and required inputs.
+/// <summary> +/// Configures UI for starting an Android activity +/// </summary> case ActMobileDevice.eMobileDeviceAction.StartActivity: xAppPnl.Visibility = Visibility.Visible; xInputLabelVE.Content = "Activity:"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; break;Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (4)
525-528: 🧹 Nitpick (assertive)Clarify iOS-specific keyboard action in enum description.
The description "Type Using keyboard" doesn't clearly indicate that this is primarily for iOS keyboard simulation (as shown in the implementation and UI note). Consider updating the description to be more specific.
- [EnumValueDescription("Type Using keyboard")] + [EnumValueDescription("Type Using iOS keyboard")] TypeUsingIOSkeyboard,
553-554: 🧹 Nitpick (assertive)Correct capitalization in WiFi enum description.
As noted in previous reviews, use consistent capitalization for "WiFi" in the enum description.
- [EnumValueDescription("Toggle WIFI")] + [EnumValueDescription("Toggle WiFi")] ToggleWifi,
525-569: 🧹 Nitpick (assertive)Consider adding enum value grouping or categorization.
With the significant expansion of mobile device actions (now over 45 operations), it might be beneficial to organize these enum values into logical categories, either through comments, regions, or a nested enum approach. This would improve maintainability as the list continues to grow.
For example, you could add region directives to group related actions:
public enum eMobileDeviceAction { + #region Touch Interaction [EnumValueDescription("Press XY")] PressXY, // other touch-related actions... + #endregion + #region Device Controls [EnumValueDescription("Press Back Button")] PressBackButton, // other device control actions... + #endregion + #region App Management [EnumValueDescription("Open App")] OpenApp, // other app management actions... + #endregion + #region Network & Connectivity [EnumValueDescription("Toggle WiFi")] ToggleWifi, // other network-related actions... + #endregion // etc. }
158-169: 💡 Verification agent🧩 Analysis chain
Remove commented note and verify if property is needed.
The comment "// need to check" suggests uncertainty about this property. Verify if this property is required and remove the comment if it is.
-public ActInputValue LocalFolderPathInput // need to check +public ActInputValue LocalFolderPathInputRun this script to check if the property is used elsewhere in the codebase:
🏁 Script executed:
#!/bin/bash # Check for usage of LocalFolderPathInput in the codebase rg "LocalFolderPathInput" --type csLength of output: 579
🏁 Script executed:
#!/bin/bash # List files in the UI/Mobile directory echo "Files in ActionsLib/UI/Mobile:" ls Ginger/GingerCoreNET/ActionsLib/UI/Mobile # Search for LocalFolderPathInput across all file types (including XAML) echo -e "\nSearching for 'LocalFolderPathInput' in all files:" rg "LocalFolderPathInput" -nLength of output: 884
Remove the inline “need to check” comment and clean up the unused property
I didn’t find any references to
LocalFolderPathInputoutside of its own declaration (no usages in code or XAML), so the comment can be dropped—and if this input isn’t actually used by the mobile‐device action, you may want to delete the entire property.• File to update:
- Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs
• Suggested diff:
-public ActInputValue LocalFolderPathInput // need to check +public ActInputValue LocalFolderPathInputIf you confirm the property isn’t needed at runtime or in the UI, remove lines 158–169 altogether.
Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (6)
46-56: Unusedusingdirectives still present
CassandraandNUglify.Htmlnamespaces are still imported but never referenced, so the compiler will emit warnings and you pull two heavy transitive dependencies for no benefit.
Please delete these directives or use conditional compilation.
4113-4116:throw new($"…")is still invalid C# syntaxThe same compile-time error that was flagged earlier remains:
throw new($"Failed to get app identifier …");
newmust be followed by a concrete exception type.- throw new($"Failed to get app identifier attribute name: {ex.Message}"); + throw new InvalidOperationException($"Failed to get app identifier attribute name: {ex.Message}", ex);
4377-4383: Device path assembled withPath.Combinebreaks on non-Windows devices
Path.Combine(DeviceTargerFolder, Path.GetFileName(filePath))inserts back-slashes on Windows hosts, yielding an invalid device path (/sdcard\photo.png).
Use/explicitly for the remote end:- var remoteFilePath = Path.Combine(DeviceTargerFolder, Path.GetFileName(filePath)); + var remoteFilePath = $"{DeviceTargerFolder.TrimEnd('/')}/{Path.GetFileName(filePath)}";
4573-4579:IsAlphaUpper()is not a BCL method – will not compile
charhas noIsAlphaUpper()extension in the core libraries.
Usechar.IsUpper(c)or add the missing extension.- if ((c.IsAlphaUpper() && !isShiftActive) || (Char.IsLower(c) && isShiftActive)) + if ((char.IsUpper(c) && !isShiftActive) || (char.IsLower(c) && isShiftActive))
4821-4830: 🧹 Nitpick (assertive)
⚠️ Potential issueSynchronous
Thread.Sleepblocks the driver thread
LockForDurationusesThread.Sleepto wait while the device is locked.
This blocks the STA thread and the agent cannot receive cancellation or UI events.Replace with an asynchronous delay:
- Thread.Sleep(1000 * int.Parse(time)); + await Task.Delay(TimeSpan.FromSeconds(seconds), CancellationToken.None);
4121-4131: 🛠️ Refactor suggestion
⚠️ Potential issue
SetFilePath– Incorrect path construction & exception usage
Path.GetFileName(FilePath)returns the directory name only when the path ends with a back-slash; otherwise you lose the filename for single-file inputs.- The successful branch concatenates
"{FilePath}.{FileType}", dropping the original filename and creatingc:\dir\.<ext>.- Mixing
Path.Combine(back-slash) with the device path produced elsewhere could introduce invalid paths on Linux/Android.throw new("…")again omits an exception type.Suggested fix:
- string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); - string fileName = Path.GetFileName(FilePath); - string targetFile = string.IsNullOrEmpty(fileName) ? Path.Combine(FilePath, $"{FileName}_{timestamp}.{FileType}") : $"{FilePath}.{FileType}"; + if (!Directory.Exists(FilePath)) + throw new DirectoryNotFoundException($"Directory '{FilePath}' does not exist"); + string safeExtension = FileType.TrimStart('.'); + string baseName = string.IsNullOrEmpty(FileName) ? "file" : FileName; + string targetFile = Path.Combine( + FilePath, + $"{baseName}_{DateTime.Now:yyyyMMddHHmmss}.{safeExtension}");
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml(2 hunks)Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs(6 hunks)Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs(3 hunks)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs(12 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (2)
Ginger/GingerCoreCommon/Actions/Act.cs (1)
AddOrUpdateInputParamValue(825-848)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (21)
GrantAppPermission(5090-5118)TypeUsingIOSkeyboard(4620-4648)ClearAppData(4665-4691)ScreenSize(4756-4770)OpenNotificationsPanel(4771-4788)GetDeviceTime(4789-4800)GetAppPackage(987-1031)GetCurrentActivityDetails(2113-2145)LockForDuration(4802-4836)GetSettings(4837-4864)ToggleLocationServices(4930-4946)ToggleData(4947-4971)ToggleAirplaneMode(4973-4997)ToggleWifi(4998-5021)IsIMEActive(5022-5036)GetIMEActiveEngine(5037-5051)StartActivity(5052-5069)GetGeoLocation(5070-5088)SendAppToBackground(5119-5142)SetNetworkConnection(5143-5160)GetDeviceOSType(4649-4664)
🔇 Additional comments (4)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml (1)
26-28: Added text block for input guidance.The addition of a labeled TextBlock for providing contextual help or guidance for inputs is a good improvement for user experience.
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (3)
299-300: Added support for ClearAppData operation.New case added to handle the ClearAppData mobile device action by showing the app panel.
334-339: Enhanced file transfer UI with helpful text.Added explanatory text for multiple file selection when pushing files to device, improving user guidance.
343-350: Fixed pull file operation labels.Corrected the labels for file pull operation to accurately describe the source and target locations.
There was a problem hiding this comment.
Actionable comments posted: 3
🔭 Outside diff range comments (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (1)
19-35: 🧹 Nitpick (assertive)Duplicate license header – remove redundancy
The file contains the full Apache-2 license block twice.
Keeping both adds unnecessary noise, complicates future merges, and inflates the diff-stat.-#region License -/* -… second, identical license header … -*/ -#endregionPlease delete the duplicated block and keep a single header at the top of the file.
♻️ Duplicate comments (10)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (5)
357-361: Add validation for iOS-specific typing action.The
TypeUsingIOSkeyboardaction is primarily targeted at iOS devices as indicated by the note in the UI. Consider adding a runtime check to validate if the device is iOS before attempting to execute.
371-375: Add input validation for time duration inputs.For
LockForDurationaction that requires time in seconds, there's no validation to ensure users enter numeric values or reasonable durations. Consider adding validation to prevent runtime errors.
380-385: Consider adding documentation for the new actions.The new action
GrantAppPermissionis added without comments explaining its purpose or expected inputs. Adding XML documentation would improve maintainability.
392-397: Consider adding documentation for the new actions.The new action
StartActivityis added without comments explaining its purpose or expected inputs. Adding XML documentation would improve maintainability.
84-84: 🛠️ Refactor suggestionConsistent naming is needed for folder path textboxes.
The naming scheme between
xFolderPathTxtBoxand what appears to be a similar control elsewhere (xFolderPathTextBox) is inconsistent and could cause confusion during maintenance.Consider renaming the controls to follow a more descriptive and consistent naming convention that reflects their purpose, such as:
-xFolderPathTxtBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); +xDeviceFolderPathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*");Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (5)
54-54: Unused using directive was already flagged earlier
using NUglify.Html;is still not referenced anywhere and will continue to trigger CS8019.The previous review comment on this exact line still applies.
Please remove the directive (or use the type) to avoid the warning.
4821-4824: SynchronousThread.Sleepblocks the STA threadThe earlier review pointed this out;
Thread.Sleepis still used inLockForDuration.
Replace with an asynchronous wait (await Task.Delay(…)with aCancellationToken) to keep the agent responsive.
4573-4577:⚠️ Potential issue
IsAlphaUpper()causes compile error – usechar.IsUpper
charhas noIsAlphaUpper()method (unless an extension is defined elsewhere).- if ((c.IsAlphaUpper() && !isShiftActive) || (Char.IsLower(c) && isShiftActive)) + if ((char.IsUpper(c) && !isShiftActive) || (char.IsLower(c) && isShiftActive))
4112-4115:⚠️ Potential issue
throw newwithout exception type – code will not compileThe C# compiler expects a concrete exception type after
new.- throw new($"Failed to get app identifier attribute name: {ex.Message}"); + throw new InvalidOperationException($"Failed to get app identifier attribute name: {ex.Message}", ex);Search & replace the same pattern throughout the file (
throw new($"…")) to unblock the build.
4120-4126: 🛠️ Refactor suggestion
SetFilePathstill has parameter shadowing & malformed path logic
fileNameshadows theFileNameparameter and the else-branch appends the extension to the directory ("C:\tmp\logs.txt"➜"C:\tmp\.txt").- if (!string.IsNullOrEmpty(FilePath) && Directory.Exists(FilePath)) - { - string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); - string fileName = Path.GetFileName(FilePath); - string targetFile = string.IsNullOrEmpty(fileName) ? Path.Combine(FilePath, $"{FileName}_{timestamp}.{FileType}") : $"{FilePath}.{FileType}"; - return targetFile; - } + if (string.IsNullOrWhiteSpace(FilePath) || !Directory.Exists(FilePath)) + throw new DirectoryNotFoundException($"Directory '{FilePath}' does not exist"); + + string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); + string baseName = string.IsNullOrWhiteSpace(FileName) ? "file" : Path.GetFileNameWithoutExtension(FileName); + string targetName = $"{baseName}_{timestamp}.{FileType.TrimStart('.')}"; + return Path.Combine(FilePath, targetName);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs(5 hunks)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs(11 hunks)
🧰 Additional context used
🧠 Learnings (1)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (1)
Learnt from: prashelke
PR: Ginger-Automation/Ginger#3429
File: Ginger/Ginger/AutomatePageLib/AddActionMenu/WindowExplorer/Common/WindowExplorerPage.xaml.cs:1123-1126
Timestamp: 2024-07-26T22:04:12.930Z
Learning: The user has removed an unnecessary empty line at 1123 in `WindowExplorerPage.xaml.cs` for better code compactness.
🧬 Code Graph Analysis (1)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (2)
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (1)
ActMobileDevice(30-680)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (10)
ActMobileDevice(1855-1865)ClearAppData(4664-4690)PullFileFromDevice(4412-4438)SetClipboardText(4440-4465)TypeUsingIOSkeyboard(4619-4647)LockForDuration(4801-4835)PerformMultiTouch(1795-1837)GrantAppPermission(5089-5117)SendAppToBackground(5118-5141)StartActivity(5051-5068)
🔇 Additional comments (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (1)
4665-4682:ClearAppDatanot implemented for iOSThe comment hints at
ResetApp()but the method currently throws for iOS devices.
Consider implementing the iOS equivalent (e.g.,Driver.ResetApp()or relaunch-with-args) or clearly document that the action is Android-only.
| xFolderPathLbl.Content = "Device File to Pull:"; | ||
| xFilePathLbl.Content = "Local Target to Push:"; | ||
| xFileTextBlock.Text = ""; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Verify label text accuracy for file operations.
The label text "Local Target to Push" for pulling a file from a device seems incorrect. When pulling a file, you're not pushing anything.
Apply this change to correct the label text:
xFolderPathLbl.Content = "Device File to Pull:";
-xFilePathLbl.Content = "Local Target to Push:";
+xFilePathLbl.Content = "Local Target Folder:";
xFileTextBlock.Text = "";📝 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. Thoroughly test & benchmark the code to ensure it meets the requirements.
| xFolderPathLbl.Content = "Device File to Pull:"; | |
| xFilePathLbl.Content = "Local Target to Push:"; | |
| xFileTextBlock.Text = ""; | |
| xFolderPathLbl.Content = "Device File to Pull:"; | |
| xFilePathLbl.Content = "Local Target Folder:"; | |
| xFileTextBlock.Text = ""; |
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 342 to 344, the label text "Local Target to Push:" is inaccurate for the file pull operation. Change this label to reflect that it is the local destination for the pulled file, such as "Local Target to Pull:" or "Local Target to Save:". Update the xFilePathLbl.Content assignment accordingly to correct the label text.
| case ActMobileDevice.eMobileDeviceAction.SendAppToBackground: | ||
| xInputLabelVE.Content = "Set a Time Duration for Backgroud(Seconds):"; | ||
| xInputTextBlock.Text = ""; | ||
| xInputPnl.Visibility = Visibility.Visible; | ||
| break; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix typo in label text and add input validation.
There's a typo in the label text ("Backgroud" instead of "Background"), and as with other duration inputs, there's no validation to ensure numeric values.
Apply these changes to fix the typo and add validation:
case ActMobileDevice.eMobileDeviceAction.SendAppToBackground:
- xInputLabelVE.Content = "Set a Time Duration for Backgroud(Seconds):";
+ xInputLabelVE.Content = "Set a Time Duration for Background(Seconds):";
xInputTextBlock.Text = "";
xInputPnl.Visibility = Visibility.Visible;
+ // Add validation for numeric input in seconds
+ xInputVE.ValueTextBox.PreviewTextInput += (s, e) =>
+ {
+ e.Handled = !char.IsDigit(e.Text[0]) && !char.IsPunctuation(e.Text[0]);
+ };
break;📝 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. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case ActMobileDevice.eMobileDeviceAction.SendAppToBackground: | |
| xInputLabelVE.Content = "Set a Time Duration for Backgroud(Seconds):"; | |
| xInputTextBlock.Text = ""; | |
| xInputPnl.Visibility = Visibility.Visible; | |
| break; | |
| case ActMobileDevice.eMobileDeviceAction.SendAppToBackground: | |
| xInputLabelVE.Content = "Set a Time Duration for Background(Seconds):"; | |
| xInputTextBlock.Text = ""; | |
| xInputPnl.Visibility = Visibility.Visible; | |
| // Add validation for numeric input in seconds | |
| xInputVE.ValueTextBox.PreviewTextInput += (s, e) => | |
| { | |
| e.Handled = !char.IsDigit(e.Text[0]) && !char.IsPunctuation(e.Text[0]); | |
| }; | |
| break; |
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 387 to 391, correct the typo in the label text from "Backgroud" to "Background". Additionally, implement input validation for the duration input to ensure only numeric values are accepted, consistent with other duration inputs. This validation should prevent invalid entries and provide user feedback if necessary.
| foreach (var filePath in Directory.GetFiles(LocalFilePath)) | ||
| { | ||
| var remoteFilePath = Path.Combine(DeviceTargerFolder, Path.GetFileName(filePath)); | ||
| try | ||
| { | ||
| Driver.PushFile(remoteFilePath, new FileInfo(filePath)); | ||
| } | ||
| catch (Exception ex) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Remote path construction will break on non-Windows devices
Path.Combine inserts back-slashes on Windows; Android/iOS expect a forward-slash.
- var remoteFilePath = Path.Combine(DeviceTargerFolder, Path.GetFileName(filePath));
+ var remoteFilePath = $"{DeviceTargerFolder.TrimEnd('/')}/{Path.GetFileName(filePath)}";Please update both the directory loop and the single-file branch.
🤖 Prompt for AI Agents (early access)
In Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs around lines 4376 to 4383, the remote file path is constructed using Path.Combine, which uses backslashes on Windows but remote devices like Android/iOS require forward slashes. Replace Path.Combine with a method that joins paths using forward slashes or manually concatenate the paths with '/' to ensure compatibility. Apply this fix both in the directory loop and the single-file handling branch to prevent path issues on non-Windows devices.
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (10)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (4)
372-376: 🛠️ Refactor suggestionAdd input validation for time duration.
For
LockForDurationaction that requires time in seconds, there's no validation to ensure users enter numeric values or reasonable durations. This could lead to runtime errors if invalid values are entered.case ActMobileDevice.eMobileDeviceAction.LockForDuration: xInputLabelVE.Content = "Set a Time Duration for Lock(Seconds):"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; + // Add validation for numeric input in seconds + xInputVE.ValueTextBox.PreviewTextInput += (s, e) => + { + e.Handled = !char.IsDigit(e.Text[0]) && !char.IsPunctuation(e.Text[0]); + }; break;
358-362: 🛠️ Refactor suggestionAdd validation for platform compatibility in iOS keyboard action.
The TypeUsingIOSkeyboard action appears to be iOS-specific as noted in the UI text. Consider adding runtime validation to check if the device is iOS before execution.
case ActMobileDevice.eMobileDeviceAction.TypeUsingIOSkeyboard: xInputLabelVE.Content = "Text:"; xInputTextBlock.Text = "Note: For IOS, Keyboard Should be Open."; + // Add warning message for Android devices + if (mContext?.RunsetExecutor?.CurrentActivity?.CurrentDriver?.IsDriverTypeAppiumAndroid == true) + { + xInputTextBlock.Text += "\nWARNING: This action is optimized for iOS. For Android, consider using standard input methods."; + } xInputPnl.Visibility = Visibility.Visible; break;
388-392:⚠️ Potential issueFix typo in label text and add input validation.
There's a typo in the label text ("Backgroud" instead of "Background") and, similar to other duration inputs, there's no validation to ensure numeric values are entered.
case ActMobileDevice.eMobileDeviceAction.SendAppToBackground: - xInputLabelVE.Content = "Set a Time Duration for Backgroud(Seconds):"; + xInputLabelVE.Content = "Set a Time Duration for Background(Seconds):"; xInputTextBlock.Text = ""; xInputPnl.Visibility = Visibility.Visible; + // Add validation for numeric input in seconds + xInputVE.ValueTextBox.PreviewTextInput += (s, e) => + { + e.Handled = !char.IsDigit(e.Text[0]) && !char.IsPunctuation(e.Text[0]); + }; break;
342-342:⚠️ Potential issueFix incorrect label text for file pull operation.
The label text "Local Target to Push" is inaccurate for the file pull operation. When pulling a file, you're retrieving it from the device, not pushing it.
-xFolderPathLbl.Content = "Local Target to Push:"; +xFolderPathLbl.Content = "Local Target Folder:";Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (6)
54-54: Unusedusing NUglify.Html;directive still present
Previous review already pointed out that this namespace is never referenced in the file. Keeping it continues to add an unnecessary dependency and warnings. Please remove it.
73-74: Blocking calls withThread.Sleephurt responsiveness
Thread.Sleepis now used in several new helper methods (LockForDuration,StartNetworkCapture, …). These calls block the STA/UI thread and prevent Ginger from processing cancellation or UI events.
Replace them with asynchronous delays (e.g.,await Task.Delay(...)with a cancellation token) or native Appium wait utilities.Also applies to: 4821-4824, 4897-4899
4112-4115: Compile-time error – invalidthrow newsyntax
throw new($"Failed to get app identifier attribute name: {ex.Message}");
C# requires an exception type afternew. UseInvalidOperationException(or a more specific type).
This issue was raised before and is still unfixed.
4120-4131:SetFilePathstill suffers from variable shadowing and malformed path construction
string fileName = Path.GetFileName(FilePath);shadows theFileNameparameter and later produces an incorrect path whenfileNameis empty. The resulting"${FilePath}.${FileType}"drops the original filename and may duplicate the extension.
Consider adopting the previously suggested refactor that (a) avoids shadowing, (b) validates the directory, and (c) usesPath.Combinesafely.
4376-4383: Remote path construction still Windows-centric
Path.Combine(DeviceTargerFolder, Path.GetFileName(filePath))inserts back-slashes on Windows, but Android/iOS expect forward-slashes.
Replace with explicit'/'concatenation or a helper that normalises to POSIX separators:- var remoteFilePath = Path.Combine(DeviceTargerFolder, Path.GetFileName(filePath)); + var remoteFilePath = $"{DeviceTargerFolder.TrimEnd('/')}/{Path.GetFileName(filePath)}";
4573-4577:c.IsAlphaUpper()does not exist – code will not compile
The extension method flagged in the previous review is still here.
Replace with the BCL callchar.IsUpper(c).- if (c.IsAlphaUpper() && !isShiftActive) ... + if (char.IsUpper(c) && !isShiftActive) ...
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml(2 hunks)Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs(5 hunks)Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs(3 hunks)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs(11 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (2)
Ginger/GingerCoreCommon/Actions/Act.cs (1)
AddOrUpdateInputParamValue(825-848)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (21)
GrantAppPermission(5089-5117)TypeUsingIOSkeyboard(4619-4647)ClearAppData(4664-4690)ScreenSize(4755-4769)OpenNotificationsPanel(4770-4787)GetDeviceTime(4788-4799)GetAppPackage(986-1030)GetCurrentActivityDetails(2112-2144)LockForDuration(4801-4835)GetSettings(4836-4863)ToggleLocationServices(4929-4945)ToggleData(4946-4970)ToggleAirplaneMode(4972-4996)ToggleWifi(4997-5020)IsIMEActive(5021-5035)GetIMEActiveEngine(5036-5050)StartActivity(5051-5068)GetGeoLocation(5069-5087)SendAppToBackground(5118-5141)SetNetworkConnection(5142-5159)GetDeviceOSType(4648-4663)
🔇 Additional comments (2)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml (1)
95-96: Add informative TextBlocks for file operations.The addition of descriptive TextBlocks (
xFileTextBlockandxFolderTextBlock) enhances the user interface by providing helpful guidance on file and folder operations.Also applies to: 98-99
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs (1)
158-169: New property for local folder path handling.The addition of the
LocalFolderPathInputproperty properly supports the file operation enhancements in the UI.
| case ActMobileDevice.eMobileDeviceAction.GrantAppPermission: | ||
| xAppPnl.Visibility = Visibility.Visible; | ||
| xInputLabelVE.Content = "Permission:"; | ||
| xInputTextBlock.Text = ""; | ||
| xInputPnl.Visibility = Visibility.Visible; | ||
| break; |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Consider adding documentation for new actions.
The new actions (GrantAppPermission and StartActivity) are added without comments explaining their purpose or expected inputs. Adding XML documentation would improve maintainability.
+/// <summary>
+/// Configures UI for granting app permissions
+/// </summary>
case ActMobileDevice.eMobileDeviceAction.GrantAppPermission:
xAppPnl.Visibility = Visibility.Visible;
xInputLabelVE.Content = "Permission:";
xInputTextBlock.Text = "";
xInputPnl.Visibility = Visibility.Visible;
break;
+/// <summary>
+/// Configures UI for starting Android activities
+/// </summary>
case ActMobileDevice.eMobileDeviceAction.StartActivity:
xAppPnl.Visibility = Visibility.Visible;
xInputLabelVE.Content = "Activity:";
xInputTextBlock.Text = "";
xInputPnl.Visibility = Visibility.Visible;
break;Also applies to: 393-398
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 381 to 386 and 393 to 398, the new actions GrantAppPermission and StartActivity lack XML documentation. Add XML comments above these case blocks describing the purpose of each action and the expected inputs or behavior to improve code maintainability and clarity.
| [EnumValueDescription("Grant App Permission")] | ||
| GrantAppPermission, | ||
| [EnumValueDescription("Type Using keyboard")] | ||
| TypeUsingIOSkeyboard, | ||
| [EnumValueDescription("Clear App Data")] | ||
| ClearAppData, | ||
| [EnumValueDescription("Get Screen Size")] | ||
| ScreenSize, | ||
| [EnumValueDescription("Open Notifications Panel")] | ||
| OpenNotificationsPanel, | ||
| [EnumValueDescription("Get Device Time")] | ||
| GetDeviceTime, | ||
| [EnumValueDescription("Get Orientation")] | ||
| GetOrientation, | ||
| [EnumValueDescription("Get App Package")] | ||
| GetAppPackage, | ||
| [EnumValueDescription("Get Current Activity Details")] | ||
| GetCurrentActivityDetails, | ||
| [EnumValueDescription("Lock for Duration")] | ||
| LockForDuration, | ||
| [EnumValueDescription("Get Device Settings")] | ||
| GetSettings, | ||
| [EnumValueDescription("Toggle Location Services")] | ||
| ToggleLocationServices, | ||
| [EnumValueDescription("Toggle Data")] | ||
| ToggleData, | ||
| [EnumValueDescription("Toggle Airplane Mode")] | ||
| ToggleAirplaneMode, | ||
| [EnumValueDescription("Toggle WIFI")] | ||
| ToggleWifi, | ||
| [EnumValueDescription("Is IME Active")] | ||
| IsIMEActive, | ||
| [EnumValueDescription("Get IME Active Engine")] | ||
| GetIMEActiveEngine, | ||
| [EnumValueDescription("Start Activity")] | ||
| StartActivity, | ||
| [EnumValueDescription("Get GeoLocation")] | ||
| GetGeoLocation, | ||
| [EnumValueDescription("Send App to Background")] | ||
| SendAppToBackground, | ||
| [EnumValueDescription("Set Network Connection")] | ||
| SetNetworkConnection, | ||
| [EnumValueDescription("Get Device OS Type")] | ||
| GetDeviceOSType, |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Comprehensive set of new mobile device actions.
The enum additions provide a well-rounded set of mobile device operations, which are appropriately implemented in the Appium driver. These actions significantly enhance mobile automation capabilities.
However, I recommend clarifying that the TypeUsingIOSkeyboard action is primarily for iOS in its description:
-[EnumValueDescription("Type Using keyboard")]
+[EnumValueDescription("Type Using iOS keyboard")]
TypeUsingIOSkeyboard,Additionally, consider organizing these enum values into logical categories using region directives for better maintainability as the list continues to grow:
#region App Management
[EnumValueDescription("Open App")]
OpenApp,
// Other app management actions...
#endregion
#region Device Controls
[EnumValueDescription("Toggle WIFI")]
ToggleWifi,
// Other device control actions...
#endregion🤖 Prompt for AI Agents (early access)
In Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs between lines 525 and 568, update the EnumValueDescription for TypeUsingIOSkeyboard to explicitly mention it is primarily for iOS devices. Then, organize the enum values into logical categories using #region directives, such as grouping app management actions together and device control actions separately, to improve code maintainability as the list grows.
…board name, delete LocalFolderPathInput value
There was a problem hiding this comment.
Actionable comments posted: 8
🔭 Outside diff range comments (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (1)
1-35: 🧹 Nitpick (assertive)Duplicate license banner – keep a single source of truth
The file contains two identical Apache 2.0 license headers back-to-back.
Keeping redundant blocks clutters the diff history and makes future merges noisier.
Please delete one of them.
♻️ Duplicate comments (8)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (4)
84-84: Control naming clarity needed for folder path
The controlxFolderPathTxtBoxis easily confused withxFolderPathTextBox. Consider adopting distinct, descriptive names (e.g.,xDeviceFolderPathTextBoxvs.xLocalFolderPathTextBox) to avoid maintenance errors.
340-351: Label text for PullFileFromDevice is misleading
The prompt “Local Target to Push” contradicts the pull operation. Please update to something like “Local Target Folder:” or “Local Save Path:” to reflect the correct intent.
381-386: Consider adding XML documentation for GrantAppPermission
Documenting the expected permission values and behavior will improve clarity, especially given the variety of permission types mobile platforms support.
393-398: XML documentation missing for StartActivity
Please add comments above theStartActivitycase to describe the required format (e.g., package and activity names) and any platform-specific considerations.Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (4)
54-54:using NUglify.Html;is still unusedThis directive is not referenced anywhere in the file – the
IsAlphaUpper()extension is declared locally, not provided by NUglify.
Remove it to avoid unnecessary build dependencies and warnings.
4385-4395: Back-slashes sent to the device path will break on non-Windows OSes
remoteFilePath = Path.Combine(DeviceTargerFolder, Path.GetFileName(filePath));
Path.Combineinserts ‘\’ on Windows but Android/iOS expect ‘/’.Reuse the earlier recommendation:
- var remoteFilePath = Path.Combine(DeviceTargerFolder, Path.GetFileName(filePath)); + var remoteFilePath = $"{DeviceTargerFolder.TrimEnd('/')}/{Path.GetFileName(filePath)}";
4809-4820:Thread.Sleepblocks the STA thread
LockForDurationsuspends the entire driver thread:Thread.Sleep(1000 * int.Parse(time));This prevents cancellation, UI refresh and parallel tasks.
Prefer an asynchronous delay that honours cancellation tokens, e.g.await Task.Delay(TimeSpan.FromSeconds(seconds), token);
4118-4131:⚠️ Potential issue
SetFilePathstill builds malformed pathsEdge cases remain:
- When
FilePathis a directory, theelsebranch creates
"<dir>.mp4"(extension appended to a folder name) – an invalid path.fileNameshadows theFileNameparameter, making the intent unclear.Suggested fix:
public string SetFilePath(string fileType, string directory, string baseName) { - if (!string.IsNullOrEmpty(FilePath) && Directory.Exists(FilePath)) + if (!Directory.Exists(directory)) + throw new DirectoryNotFoundException($"Directory '{directory}' does not exist"); - string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); - string fileName = Path.GetFileName(FilePath); - string targetFile = string.IsNullOrEmpty(fileName) ? Path.Combine(FilePath, $"{FileName}_{timestamp}.{FileType}") : $"{FilePath}.{FileType}"; - return targetFile; + string timeStamp = DateTime.Now.ToString("yyyyMMddHHmmss"); + baseName ??= "file"; + string targetName = $"{baseName}_{timeStamp}.{fileType.TrimStart('.')}"; + return Path.Combine(directory.TrimEnd(Path.DirectorySeparatorChar), targetName); }This creates a valid filename regardless of whether the caller passed a directory or file, avoids shadowing, and stays cross-platform.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs(5 hunks)Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs(9 hunks)
🧰 Additional context used
🧠 Learnings (1)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (1)
Learnt from: prashelke
PR: Ginger-Automation/Ginger#3429
File: Ginger/Ginger/AutomatePageLib/AddActionMenu/WindowExplorer/Common/WindowExplorerPage.xaml.cs:1123-1126
Timestamp: 2024-07-26T22:04:12.930Z
Learning: The user has removed an unnecessary empty line at 1123 in `WindowExplorerPage.xaml.cs` for better code compactness.
🔇 Additional comments (4)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (4)
287-291: Clearing input for OpenDeeplink is correct
Explicitly resettingxInputTextBlock.Textensures no residual text remains when switching actions, and the label “Link:” clearly indicates expected input.
302-306: Clearing previous input on SetContext is appropriate
ResettingxInputTextBlock.Textavoids showing stale context values when the action changes.
308-312: Resetting script input field prevents residual commands
Good practice to clear the text block so users aren’t misled by a previous value when switching to the RunScript action.
353-357: Clearing clipboard input text is good
ResettingxInputTextBlock.Textensures no leftover text when switching actions.
| xInputLabelVE.Content = "Note: Max duration recording: 30 min."; | ||
| xInputTextBlock.Text = ""; | ||
| xInputVE.Visibility = Visibility.Collapsed; | ||
| xInputPnl.Visibility = Visibility.Visible; |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Consider moving static hint text to resource files
Hardcoded UI hints like “Note: Max duration recording: 30 min.” should live in localization resources to support translations and easier updates.
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 315 to 318, the UI hint text "Note: Max duration recording: 30 min." is hardcoded. Move this string to the localization resource files and replace the hardcoded text with a reference to the resource key to enable easier translations and updates.
| case ActMobileDevice.eMobileDeviceAction.SendAppToBackground: | ||
| xInputLabelVE.Content = "Set a Time Duration for Background(Seconds):"; | ||
| xInputTextBlock.Text = ""; | ||
| xInputPnl.Visibility = Visibility.Visible; | ||
| break; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Missing numeric validation for background duration
As with other duration-based inputs, enforce numeric-only entries for “SendAppToBackground” to avoid invalid durations.
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 388 to 392, the input for the "SendAppToBackground" action duration lacks numeric validation. Add validation logic to ensure that the user can only enter numeric values for the background duration input, similar to other duration-based inputs, to prevent invalid entries.
| case ActMobileDevice.eMobileDeviceAction.PushFileToDevice: | ||
| xFilePathLbl.Content = "Local File to Push:"; | ||
| xFolderPathLbl.Content = "Device Target Folder:"; | ||
| xFileTextBlock.Text="For Multiple Files Select Folder"; | ||
| xFilePathLbl.Visibility = Visibility.Visible; | ||
| xFilePathTextBox.Visibility = Visibility.Visible; | ||
| xFolderPathLbl.Visibility = Visibility.Visible; | ||
| xFolderPathTxtBox.Visibility = Visibility.Visible; | ||
| xFileTransferPnl.Visibility = Visibility.Visible; | ||
| xFileTransferPnl.Visibility = Visibility.Visible; | ||
| break; |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Minor formatting and punctuation
In xFileTextBlock.Text="For Multiple Files Select Folder"; add spaces around = for consistency and consider ending the sentence with a period or externalizing to a resource string.
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 330 to 339, the assignment to xFileTextBlock.Text lacks spaces around the equals sign and the string should end with a period for proper punctuation. Add spaces around the '=' operator for consistency and update the string to end with a period. Optionally, move the string to a resource file for localization support.
| case ActMobileDevice.eMobileDeviceAction.TypeUsingkeyboard: | ||
| xInputLabelVE.Content = "Text:"; | ||
| xInputTextBlock.Text = "Note: For IOS, Keyboard Should be Open."; | ||
| xInputPnl.Visibility = Visibility.Visible; | ||
| break; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Inconsistent action naming and missing validation
- The enum value
TypeUsingkeyboardbreaks PascalCase convention; rename toTypeUsingKeyboard(including updates in the enum, XAML, and driver). - Also consider adding a runtime warning or validation for non-iOS devices and input filtering to prevent unsupported usage.
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 358 to 362, rename the enum value from TypeUsingkeyboard to TypeUsingKeyboard to follow PascalCase naming conventions. Update all references to this enum value in the enum definition, related XAML files, and driver code to maintain consistency. Additionally, add runtime validation or warnings to detect when this action is used on non-iOS devices and implement input filtering to prevent unsupported usage scenarios.
| case ActMobileDevice.eMobileDeviceAction.ClearAppData: | ||
| xAppPnl.Visibility = Visibility.Visible; | ||
| break; |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Add XML documentation for ClearAppData
The new ClearAppData case is functional, but documenting its purpose above the case block will help future maintainers understand the intention without tracing driver code.
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 298 to 300, add XML documentation comments above the ClearAppData case to describe its purpose and behavior. This should briefly explain what ClearAppData does and why the xAppPnl visibility is set to visible, aiding future maintainers in understanding the code without needing to trace through the driver logic.
| case ActMobileDevice.eMobileDeviceAction.LockForDuration: | ||
| xInputLabelVE.Content = "Set a Time Duration for Lock(Seconds):"; | ||
| xInputTextBlock.Text = ""; | ||
| xInputPnl.Visibility = Visibility.Visible; | ||
| break; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Missing numeric input validation for duration
The “LockForDuration” text field should restrict entries to digits (and possibly decimals). Attach a PreviewTextInput handler to xInputVE to enforce numeric input and prevent runtime errors.
🤖 Prompt for AI Agents (early access)
In Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs around lines 372 to 376, the input field for "LockForDuration" does not validate that the entered text is numeric, which can cause runtime errors. Attach a PreviewTextInput event handler to the xInputVE control that restricts input to digits and optionally decimals by checking the input characters and rejecting non-numeric entries. This will enforce numeric input validation and prevent invalid data entry.
| ((AndroidDriver)Driver).ExecuteScript("mobile: startLogsBroadcast", new Dictionary<string, object> { | ||
| { "options", new Dictionary<string, object>{{ "logType", "logcat" } }}}); | ||
| Thread.Sleep(1000*10); | ||
| } | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Network capture helper also uses blocking Thread.Sleep
A hard-coded Thread.Sleep(1000*10); pauses the whole agent for 10 seconds.
Consider:
await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);so callers remain responsive.
🤖 Prompt for AI Agents (early access)
In Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs around lines 4885 to 4889, replace the blocking Thread.Sleep(1000*10) call with an asynchronous delay using await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken) to avoid blocking the thread and keep the caller responsive. Ensure the method is updated to be async and accepts a cancellationToken parameter to support this change.
| if (Driver is IOSDriver) | ||
| { | ||
| foreach (char c in text) | ||
| { | ||
| SelectSubKeyboard(c); | ||
| } | ||
| } | ||
| else if (Driver is AndroidDriver) | ||
| { | ||
| ((AndroidDriver)Driver).ExecuteScript("mobile: type", new Dictionary<string, object>{{ "text", text }}); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
TypeUsingIOSkeyboard – per-character XPath look-ups are extremely slow
For long strings the loop executes FindElements for every character, causing dozens of Appium round-trips.
Possible optimisations:
- Use Appium’s
mobile:typeendpoint (as you already do for Android). - Cache frequently-used key elements (shift, “123”, “#+=”).
- Build an
ActionSequenceand send it once.
This will cut typing time by an order of magnitude.
🤖 Prompt for AI Agents (early access)
In Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs around lines 4637 to 4647, the current implementation types each character on iOS by performing per-character XPath look-ups, causing many slow Appium round-trips. To fix this, replace the per-character loop with a single call to Appium’s "mobile: type" endpoint for iOS, similar to the Android implementation. Alternatively, implement caching for frequently used keys or build and send an ActionSequence to minimize round-trips and significantly improve typing performance.
Thank you for your contribution.
Before submitting this PR, please make sure:
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Style