Skip to content

Adding more Aapiium operations to mobile device action#4184

Merged
MeniKadosh1 merged 13 commits into
masterfrom
Add-Appium-Operation
May 4, 2025
Merged

Adding more Aapiium operations to mobile device action#4184
MeniKadosh1 merged 13 commits into
masterfrom
Add-Appium-Operation

Conversation

@shai1712

@shai1712 shai1712 commented Apr 24, 2025

Copy link
Copy Markdown
Collaborator

Thank you for your contribution.
Before submitting this PR, please make sure:

  • PR description and commit message should describe the changes done in this PR
  • Verify the PR is pointing to correct branch i.e. Release or Beta branch if the code fix is for specific release , else point it to master
  • Latest Code from master or specific release branch is merged to your branch
  • No unwanted\commented\junk code is included
  • No new warning upon build solution
  • Code Summary\Comments are added to my code which explains what my code is doing
  • Existing unit test cases are passed
  • New Unit tests are added for your development
  • Sanity Tests are successfully executed for New and Existing Functionality
  • Verify that changes are compatible with all relevant browsers and platforms.
  • After creating pull request there should not be any conflicts
  • Resolve all Codacy comments
  • Builds and checks are passed before PR is sent for review
  • Resolve code review comments
  • Update the Help Library document to match any feature changes

Summary by CodeRabbit

  • New Features

    • Added extensive new mobile device actions for enhanced control over app permissions, iOS keyboard input simulation, app data management, device info retrieval, screen recording, notifications, device settings toggling, geolocation, network controls, and more.
    • Enhanced the mobile device action edit page UI with additional descriptive text blocks and expanded input options for device file and folder paths.
  • Bug Fixes

    • Strengthened input validation and error handling across mobile device functionalities to improve stability and user feedback.
  • Refactor

    • Improved internal method organization and logic flow for more reliable and maintainable mobile device operations.
  • Style

    • Minor UI and code formatting refinements for consistency and clarity.

@shai1712
shai1712 requested a review from MeniKadosh1 April 24, 2025 13:23
@coderabbitai

coderabbitai Bot commented Apr 24, 2025

Copy link
Copy Markdown
Contributor

"""

Walkthrough

This 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

File(s) Change Summary
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml,
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs
Added new TextBlock elements for descriptive text and slightly adjusted widths in the mobile device action edit page UI. Added new input panels and controls for folder path inputs. Updated code-behind to initialize, manage visibility, and set text content of these controls for new and existing mobile device actions, including PushFileToDevice and PullFileFromDevice. Minor whitespace cleanup. No signature changes.
Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs Added whitespace cleanup around existing properties. Extended the eMobileDeviceAction enum with numerous new mobile device and app management actions such as GrantAppPermission, TypeUsingkeyboard, ClearAppData, ScreenSize, OpenNotificationsPanel, and others. No breaking changes; all additions are backward-compatible.
Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs Implemented support for all new mobile device actions in the Appium driver, including detailed iOS keyboard typing simulation, folder push/pull operations, device and app management, connectivity toggles, and utility methods. Enhanced input validation, exception handling, and driver null checks throughout. Added many new public methods corresponding to the extended action set. Refactored existing methods for improved robustness and clarity.

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
Loading

Possibly related PRs

  • Add Appium Operations #4074: Extensive additions of new mobile device actions, UI panels, and control bindings for Appium operations, closely related to the UI and backend extensions in this PR.
  • Upgrade appium solution #3912: Enhancements to mobile device actions and Appium driver capabilities, including input handling improvements, related to the driver changes in this PR.
  • Upgrade appium solution #3876: Added new input panels and controls for mobile device actions, modifying the same UI files and code-behind, related to UI enhancement efforts.

Suggested reviewers

  • MeniKadosh1

Poem

🐇 In Ginger’s code, new paths appear,
TextBlocks and inputs, made clear.
Typing on iOS, with care and grace,
Folder pushes find their place.
Drivers hum and devices sing,
Rabbits cheer for the changes we bring! 🎉🐰
"""

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🔭 Outside diff range comments (2)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs (2)

1-35: 🛠️ Refactor suggestion

Duplicate license header – remove the second block

Two identical #region License blocks 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 issue

REST helper leaks RestClient – make it per-request

restClient is a field but every call to GetDeviceMetricOverAPI re-initialises it, overwriting any concurrent request.
Because the driver is used from parallel Ginger runners this causes race conditions.

Instantiate a local RestClient inside the method or guard access with a lock.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 603d251 and 279956d.

📒 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 xInputTextBlock is 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 xFolderTransferPnl properly 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 xFolderPathTextBox correctly 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:

  1. App management (ClearAppdata, GrantAppPermission, StartActivity)
  2. Device control (LockForDuration, ToggleLocationServices, ToggleData, etc.)
  3. Information retrieval (ScreenSize, GetDeviceTime, GetOrientation, etc.)
  4. File operations (PushFolder)
  5. Input simulation (TypeUsingIOSkeyboard)

All enum values have appropriate descriptive attributes, making them clear in the UI.

Comment on lines +525 to +570
[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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment on lines +527 to +528
[EnumValueDescription("Type Using keyboard")]
TypeUsingIOSkeyboard,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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,

Comment thread Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs Outdated
Comment on lines +73 to 74
using System.Threading;
using System.Threading.Tasks;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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;

@coderabbitai coderabbitai Bot Apr 24, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 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:

  1. Defined elsewhere in your codebase as an extension method
  2. 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() for char type 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 eMobileDeviceAction which includes TypeUsingkeyboard as one of the actions.
  • ActMobileDevice class has a property MobileDeviceAction of type eMobileDeviceAction.
  • This class is used in GenericAppiumDriver to handle mobile device actions including TypeUsingkeyboard.

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 calls TypeUsingIOSkeyboard(act.ActionInput.ValueForDriver);
  • TypeUsingIOSkeyboard is the method that uses the IsAlphaUpper() 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.

Comment on lines +4634 to +4663
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}");
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

TypeUsingIOSkeyboard – compile-time error & heavy XPath usage

  • c.IsAlphaUpper() is not a BCL method for char; unless you added an extension elsewhere this will not compile.
    Replace with char.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:

  1. Fix the compilation error.
  2. Cache frequently-used elements (shift, numbers etc.).
  3. Build an ActionSequence or call Appium’s mobile:type endpoint instead of per-char XPath.

Comment on lines +4983 to +5006
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}");
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

PushFolder – path concatenation will break on most OSes

remoteFilePath = remoteFolderPath + Path.GetFileName(filePath);

  • If remoteFolderPath does 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)}";

Comment on lines 4125 to 4138
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");
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

SetFilePath ‑ parameter shadowing & faulty target-file logic

Issues:

  1. Local variable fileName shadows the FileName parameter → very confusing.
  2. When fileName does exist the path becomes "{FilePath}.{FileType}", dropping the original file name and probably duplicating the extension.
  3. 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.Combine to stay cross-platform.

Committable suggestion skipped: line range outside the PR's diff.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 SetControlsView method 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

📥 Commits

Reviewing files that changed from the base of the PR and between 279956d and f40cfcd.

📒 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 TypeUsingIOSkeyboard action with an appropriate note about Android limitations.


387-393: Good implementation of folder push functionality.

The UI configuration for the new PushFolder action correctly sets up the necessary controls and visibility.


303-303: LGTM - Added support for clearing app data.

Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs Outdated
Comment on lines +86 to +88
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, "*");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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, "*");

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

♻️ Duplicate comments (12)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (6)

28-28: Unused imports detected.

The imports System.Drawing.Drawing2D and System.Linq appear 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 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, "*");

375-379: Add input validation for time duration inputs.

For LockForDuration action 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 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;

399-404: Add input validation for time duration inputs.

For SendAppToBackground action 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 StartActivity is 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.Html directive is still unused – please drop it

Identical feedback was provided in an earlier review; the directive remains and is still unused.
Safe to delete.


4127-4139: SetFilePath still suffers from shadowing, path bugs & throws compilation errors

Issues (unchanged from the previous review):

  1. Local fileName shadows the parameter FileName.
  2. When fileName exists the returned path becomes "{FilePath}.{FileType}", losing the original file name and duplicating the extension.
  3. No path separator is inserted when the caller forgets a trailing slash.
  4. 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 standard char.IsUpper(c) (or define the extension).


4990-4999: PushFolder path concatenation is still fragile

var remoteFilePath = remoteFolderPath + Path.GetFileName(filePath);

If remoteFolderPath lacks 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.Sleep hampers responsiveness

Thread.Sleep(…) in LockForDuration blocks 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

📥 Commits

Reviewing files that changed from the base of the PR and between f40cfcd and df0c7ce.

📒 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.

Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs Outdated
Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs Outdated
Comment on lines +95 to +98
<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:&#10;Documents: /storage/emulated/0/Documents/&#10;Pictures: /storage/emulated/0/Pictures/&#10;Downloads: /storage/emulated/0/Download/"/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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" />

Comment on lines +101 to +105
<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>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Suggested change
<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>

Comment on lines +525 to +571
[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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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
}

Comment thread Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs Outdated

@MeniKadosh1 MeniKadosh1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments for changes and many many cleanups to do.

Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml
Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml Outdated
Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs Outdated
Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 suggestion

Add 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 suggestion

Add 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 suggestion

Add 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 LocalFolderPathInput

Run 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 cs

Length 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" -n

Length of output: 884


Remove the inline “need to check” comment and clean up the unused property

I didn’t find any references to LocalFolderPathInput outside 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 LocalFolderPathInput

If 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: Unused using directives still present

Cassandra and NUglify.Html namespaces 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# syntax

The same compile-time error that was flagged earlier remains: throw new($"Failed to get app identifier …");
new must 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 with Path.Combine breaks 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

char has no IsAlphaUpper() extension in the core libraries.
Use char.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 issue

Synchronous Thread.Sleep blocks the driver thread

LockForDuration uses Thread.Sleep to 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

  1. 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.
  2. The successful branch concatenates "{FilePath}.{FileType}", dropping the original filename and creating c:\dir\.<ext>.
  3. Mixing Path.Combine (back-slash) with the device path produced elsewhere could introduce invalid paths on Linux/Android.
  4. 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

📥 Commits

Reviewing files that changed from the base of the PR and between df0c7ce and 07ee36f.

📒 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.

Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 …
-*/
-#endregion

Please 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 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.


371-375: Add input validation for time duration inputs.

For LockForDuration action 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 GrantAppPermission is 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 StartActivity is added without comments explaining its purpose or expected inputs. Adding XML documentation would improve maintainability.


84-84: 🛠️ Refactor suggestion

Consistent naming is needed for folder path textboxes.

The naming scheme between xFolderPathTxtBox and 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: Synchronous Thread.Sleep blocks the STA thread

The earlier review pointed this out; Thread.Sleep is still used in LockForDuration.
Replace with an asynchronous wait (await Task.Delay(…) with a CancellationToken) to keep the agent responsive.


4573-4577: ⚠️ Potential issue

IsAlphaUpper() causes compile error – use char.IsUpper

char has no IsAlphaUpper() 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 new without exception type – code will not compile

The 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

SetFilePath still has parameter shadowing & malformed path logic

fileName shadows the FileName parameter 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

📥 Commits

Reviewing files that changed from the base of the PR and between 07ee36f and 643beff.

📒 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: ClearAppData not implemented for iOS

The 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.

Comment on lines +342 to +344
xFolderPathLbl.Content = "Device File to Pull:";
xFilePathLbl.Content = "Local Target to Push:";
xFileTextBlock.Text = "";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +387 to +391
case ActMobileDevice.eMobileDeviceAction.SendAppToBackground:
xInputLabelVE.Content = "Set a Time Duration for Backgroud(Seconds):";
xInputTextBlock.Text = "";
xInputPnl.Visibility = Visibility.Visible;
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +4376 to +4383
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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (10)
Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs (4)

372-376: 🛠️ Refactor suggestion

Add input validation for time duration.

For LockForDuration action 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 suggestion

Add 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 issue

Fix 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 issue

Fix 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: Unused using 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 with Thread.Sleep hurt responsiveness
Thread.Sleep is 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 – invalid throw new syntax
throw new($"Failed to get app identifier attribute name: {ex.Message}");
C# requires an exception type after new. Use InvalidOperationException (or a more specific type).
This issue was raised before and is still unfixed.


4120-4131: SetFilePath still suffers from variable shadowing and malformed path construction
string fileName = Path.GetFileName(FilePath); shadows the FileName parameter and later produces an incorrect path when fileName is 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) uses Path.Combine safely.


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 call char.IsUpper(c).

- if (c.IsAlphaUpper() && !isShiftActive) ...
+ if (char.IsUpper(c) && !isShiftActive) ...
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 643beff and 92bc838.

📒 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 (xFileTextBlock and xFolderTextBlock) 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 LocalFolderPathInput property properly supports the file operation enhancements in the UI.

Comment thread Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml Outdated
Comment on lines +381 to +386
case ActMobileDevice.eMobileDeviceAction.GrantAppPermission:
xAppPnl.Visibility = Visibility.Visible;
xInputLabelVE.Content = "Permission:";
xInputTextBlock.Text = "";
xInputPnl.Visibility = Visibility.Visible;
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment on lines +525 to +568
[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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment thread Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs Outdated
Comment thread Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs Outdated
Comment thread Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs Outdated

@MeniKadosh1 MeniKadosh1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do needed changes

…board name, delete LocalFolderPathInput value
MeniKadosh1
MeniKadosh1 previously approved these changes Apr 30, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 control xFolderPathTxtBox is easily confused with xFolderPathTextBox. Consider adopting distinct, descriptive names (e.g., xDeviceFolderPathTextBox vs. 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 the StartActivity case 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 unused

This 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.Combine inserts ‘\’ 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.Sleep blocks the STA thread

LockForDuration suspends 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

SetFilePath still builds malformed paths

Edge cases remain:

  1. When FilePath is a directory, the else branch creates
    "<dir>.mp4" (extension appended to a folder name) – an invalid path.
  2. fileName shadows the FileName parameter, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 000f041 and 141fcaf.

📒 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 resetting xInputTextBlock.Text ensures no residual text remains when switching actions, and the label “Link:” clearly indicates expected input.


302-306: Clearing previous input on SetContext is appropriate
Resetting xInputTextBlock.Text avoids 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
Resetting xInputTextBlock.Text ensures no leftover text when switching actions.

Comment on lines +315 to 318
xInputLabelVE.Content = "Note: Max duration recording: 30 min.";
xInputTextBlock.Text = "";
xInputVE.Visibility = Visibility.Collapsed;
xInputPnl.Visibility = Visibility.Visible;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment on lines +388 to +392
case ActMobileDevice.eMobileDeviceAction.SendAppToBackground:
xInputLabelVE.Content = "Set a Time Duration for Background(Seconds):";
xInputTextBlock.Text = "";
xInputPnl.Visibility = Visibility.Visible;
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Comment on lines 330 to 339
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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment on lines +358 to +362
case ActMobileDevice.eMobileDeviceAction.TypeUsingkeyboard:
xInputLabelVE.Content = "Text:";
xInputTextBlock.Text = "Note: For IOS, Keyboard Should be Open.";
xInputPnl.Visibility = Visibility.Visible;
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Inconsistent action naming and missing validation

  • The enum value TypeUsingkeyboard breaks PascalCase convention; rename to TypeUsingKeyboard (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.

Comment on lines +298 to 300
case ActMobileDevice.eMobileDeviceAction.ClearAppData:
xAppPnl.Visibility = Visibility.Visible;
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment on lines +372 to +376
case ActMobileDevice.eMobileDeviceAction.LockForDuration:
xInputLabelVE.Content = "Set a Time Duration for Lock(Seconds):";
xInputTextBlock.Text = "";
xInputPnl.Visibility = Visibility.Visible;
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Comment on lines +4885 to +4889
((AndroidDriver)Driver).ExecuteScript("mobile: startLogsBroadcast", new Dictionary<string, object> {
{ "options", new Dictionary<string, object>{{ "logType", "logcat" } }}});
Thread.Sleep(1000*10);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment on lines +4637 to +4647
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 }});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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:

  1. Use Appium’s mobile:type endpoint (as you already do for Android).
  2. Cache frequently-used key elements (shift, “123”, “#+=”).
  3. Build an ActionSequence and 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.

@MeniKadosh1
MeniKadosh1 merged commit 4857072 into master May 4, 2025
@MeniKadosh1
MeniKadosh1 deleted the Add-Appium-Operation branch May 4, 2025 12:38
@coderabbitai coderabbitai Bot mentioned this pull request Sep 29, 2025
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants