Skip to content

Comments

Files App - Copy, Cut, Paste Actions#510

Open
Shadowtrance wants to merge 6 commits intoTactilityProject:mainfrom
Shadowtrance:files-app-copy-cut-paste
Open

Files App - Copy, Cut, Paste Actions#510
Shadowtrance wants to merge 6 commits intoTactilityProject:mainfrom
Shadowtrance:files-app-copy-cut-paste

Conversation

@Shadowtrance
Copy link
Contributor

@Shadowtrance Shadowtrance commented Feb 22, 2026

Files App - Copy, Cut, Paste Actions added + overwrite detection alert prompt.
and some bonus symbol exports

Summary by CodeRabbit

  • New Features

    • Added Copy, Cut, and Paste actions to the Files app with a persistent clipboard and a Paste button.
    • Recursive directory copy with partial-cleanup on failure.
  • Improvements

    • Safer conflict and rename handling with prompts to prevent accidental overwrites.
    • Clipboard-driven UI visibility and state updates during file operations.
  • Documentation

    • Removed a completed TODO from the high-priority task list.

and some bonus symbol exports
@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds clipboard-based file operations (copy, cut, paste) to the Files app: new State fields and APIs, View UI elements and handlers, unified showActions flow, paste implementation with recursive copy/move helpers and conflict checks, and UI/state refresh after operations. Appends LVGL module symbols (lv_obj_set_style_min_height, lv_obj_set_style_max_height, lv_group_get_editing, lv_anim_path_ease_out, lv_anim_path_ease_in, lv_async_call). Exports libc symbols strcasecmp and strncasecmp. Removes a documentation TODO entry and an unused include.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Files App - Copy, Cut, Paste Actions' directly and clearly summarizes the main changes: it adds copy, cut, and paste functionality to the Files App.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
Modules/lvgl-module/source/symbols.c (1)

413-414: Consider reversing the ease_in/ease_out ordering for consistency.

Both lv_anim_path_ease_in and lv_anim_path_ease_out are valid, confirmed LVGL path callbacks. However, ease_out is listed before ease_in — the reverse of the convention used by lv_anim_path_ease_in_out directly above. Minor cosmetic nit.

✨ Proposed reorder
-    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_out),
-    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_in),
+    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_in),
+    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_out),
Tactility/Private/Tactility/app/files/State.h (1)

77-78: pending_paste_dst accessors lack mutex protection unlike sibling clipboard methods.

setClipboard/getClipboard/hasClipboard/clearClipboard all acquire the mutex, but getPendingPasteDst() and setPendingPasteDst() do not, even though they participate in the same cross-callback paste workflow (set in onPastePressed, read in onResult). This is likely safe today because both run on the UI thread, but the inconsistency could bite if the threading model changes. Consider either wrapping these in mutex.withLock for consistency or adding a comment documenting the single-thread assumption.

Tactility/Source/app/files/View.cpp (2)

350-378: showActionsForDirectory and showActionsForFile share nearly identical code.

Both methods now have four identical button creations (Copy, Cut, Rename, Delete). Consider extracting common action buttons into a shared helper, adding file-specific buttons as needed.


658-663: Lock acquired on src, but the existence check is against dst — the lock doesn't protect the TOCTOU gap on the destination.

file::getLock(src) guards the source path, while stat(dst.c_str(), &st) checks the destination. Between lock->unlock() (Line 663) and the actual write inside doPaste, another operation could create a file at dst. On a single-user embedded device this is low-risk, but the lock here gives a false sense of safety. Consider either locking dst instead (or additionally), or removing the source lock from this check since it doesn't protect anything meaningful here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
Modules/lvgl-module/source/symbols.c (1)

411-414: Optional: reorder ease_in / ease_out before ease_in_out

The existing lv_anim_path_ease_in_out (line 411) was inserted before ease_in and ease_out, producing a slightly counter-intuitive read order. Consider reordering for consistency:

♻️ Proposed reorder
-    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_in_out),
     DEFINE_MODULE_SYMBOL(lv_anim_path_linear),
+    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_in),
+    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_out),
+    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_in_out),
-    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_in),
-    DEFINE_MODULE_SYMBOL(lv_anim_path_ease_out),
Tactility/Source/app/files/View.cpp (1)

124-143: copyRecursive leaves a partial destination directory on failure.

copyFileContents correctly removes a partial file on error (line 119). But when copyRecursive fails mid-directory traversal, the partially-populated destination directory (and any already-copied children) are not removed. The caller never cleans up the partial tree.

Consider rolling back on failure, e.g.:

♻️ Proposed fix
 static bool copyRecursive(const std::string& src, const std::string& dst) {
     if (file::isDirectory(src)) {
         if (!file::findOrCreateDirectory(dst, 0755)) {
             return false;
         }
         bool success = true;
         file::listDirectory(src, [&](const dirent& entry) {
             if (!success) return;
             if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0) return;
             auto child_src = file::getChildPath(src, entry.d_name);
             auto child_dst = file::getChildPath(dst, entry.d_name);
             if (!copyRecursive(child_src, child_dst)) {
                 success = false;
             }
         });
+        if (!success) {
+            file::deleteRecursively(dst); // remove partial copy
+        }
         return success;
     } else {
         return copyFileContents(src, dst);
     }
 }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
Tactility/Source/app/files/View.cpp (1)

539-544: pendingAction not reset before the "Rename failed" informational dialog — inconsistent with doPaste pattern.

When the destination already exists, alertdialog::start("Rename failed", ...) is shown but pendingAction remains ActionRename. On dismiss, onResult re-enters ActionRename and calls inputdialog::getResult on an alertdialog bundle; if that returns empty string the guard !new_name.empty() saves it — but this is fragile. doPaste consistently calls state->setPendingAction(State::ActionNone) before any informational (non-choice) alert. Apply the same pattern here:

♻️ Proposed fix
             if (stat(rename_to.c_str(), &st) == 0) {
                 LOGGER.warn("Rename: destination already exists: \"{}\"", rename_to);
                 lock->unlock();
+                state->setPendingAction(State::ActionNone);
                 alertdialog::start("Rename failed", "\"" + new_name + "\" already exists.");
                 break;
             }

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.

1 participant