Skip to content

Favorites inside a renamed or deleted folder keep the old path and are later silently removed #513

Open

Description

@XYIheng

Checklist

  • I can reproduce the bug with the latest version given here.
  • I made sure that there are no existing issues - open or closed - to which I could contribute my information.
  • I made sure that there are no existing discussions - open or closed - to which I could contribute my information.
  • I have read the FAQs inside the app (Menu -> About -> FAQs) and my problem isn't listed.
  • I have taken the time to fill in all the required details. I understand that the bug report will be dismissed otherwise.
  • This issue contains only one bug.
  • I have read and understood the contribution guidelines.

Affected app version

1.6.2

Affected Android/Custom ROM version

16

Affected device model

XIAOMI 17 PRO MAX

How did you install the app?

F-Droid / IzzyOnDroid

Steps to reproduce the bug

  1. Create the folders Internal/Docs/Projects and Internal/Notes.
  2. Open Docs/Projects → ⋮ → Add to favorites. Open Notes → ⋮ → Add to favorites.
  3. Go to Internal. Long-press Notes → Rename → Notes2. Long-press Docs → Rename → Docs2.
  4. Tap the Go to favorite icon (folder) in the top bar.
  5. Tap the entry "Internal / Docs / Projects".
  6. Force-stop the app, reopen it and tap Go to favorite again.

Expected behavior

The favorite follows the rename and becomes "Internal / Docs2 / Projects", just as "Internal / Notes" became "Internal / Notes2".

Actual behavior

  • Step 4: "Notes" was updated to "Notes2", but the favorite still reads "Internal / Docs / Projects".
  • Step 5: tapping it silently opens the Internal root.
  • Step 6: after a restart the favorite is gone. It is removed without any notice.

Screenshots/Screen recordings

Screenshots/Screen recordings

Before renaming After renaming Tapping stale favorite
ignoreImageMinify ignoreImageMinify ignoreImageMinify
Favorites before renaming. After renaming Notes → Notes2 and Docs → Docs2: Notes2 is updated, "Docs / Projects" is not. Tapping the stale favorite opens the Internal root.

Additional information

Tested on 1.6.2 (F-Droid build); the code on current master is unchanged:

The single-item rename moves only the favorite whose path equals the renamed path (config.moveFavorite(oldPath, it)), and the multi-item rename branches (RenameItemsDialog, RenameDialog) do not touch favorites:

private fun displayRenameDialog() {
val fileDirItems = getSelectedFileDirItems()
val paths = fileDirItems.asSequence().map { it.path }.toMutableList() as ArrayList<String>
when {
paths.size == 1 -> {
val oldPath = paths.first()
RenameItemDialog(activity, oldPath) {
config.moveFavorite(oldPath, it)
activity.runOnUiThread {
listener?.refreshFragment()
finishActMode()
}
}
}
fileDirItems.any { it.isDirectory } -> RenameItemsDialog(activity, paths) {
activity.runOnUiThread {
listener?.refreshFragment()
finishActMode()
}
}
else -> RenameDialog(activity, paths, false) {
activity.runOnUiThread {
listener?.refreshFragment()
finishActMode()
}
}
}

moveFavorite / removeFavorite only handle an exact path match:

fun moveFavorite(oldPath: String, newPath: String) {
if (!favorites.contains(oldPath)) {
return
}
val currFavorites = HashSet<String>(favorites)
currFavorites.remove(oldPath)
currFavorites.add(newPath)
favorites = currFavorites
}
fun removeFavorite(path: String) {
if (!favorites.contains(path)) {
return
}
val currFavorites = HashSet<String>(favorites)
currFavorites.remove(path)
favorites = currFavorites
}

Delete removes only the exact path of each deleted item:

config.removeFavorite(getItemWithKey(key)?.path ?: "")

On the next cold start, checkInvalidFavorites deletes every favorite whose path no longer exists:

private fun checkInvalidFavorites() {
ensureBackgroundThread {
config.favorites.forEach {
if (!isPathOnOTG(it) && !isPathOnSD(it) && !File(it).exists()) {
config.removeFavorite(it)
}
}
}
}

Related: SimpleMobileTools/Simple-File-Manager#165 (2018) added updating favorites on rename/delete, but only for the renamed/deleted folder itself, not for favorites below it.

A possible fix: when moving or removing a favorite, also rewrite or remove favorites whose path starts with oldPath + "/", and do the same in the multi-item rename callbacks.

Activity

  1. added
    bugSomething is not working
    needs triageIssue is not yet ready for PR authors to take up
    on Oct 21, 2026
  2. pengusto commented on Oct 21, 2026

    @pengusto

    I reproduced the nested-favorite rename case on the official Fossify File Manager 1.6.2 APK in an isolated Android 15 ARM64 emulator. After Docs → Docs2, Docs/Projects stayed in favorites although the real directory was now Docs2/Projects.

    I implemented an optional, version-specific workaround in Penguin Patches, compatible with Morphe:

    • Rewrite exact/descendant favorite paths only after a successful rename callback, including the shared operation used by single and multiple rename dialogs.
    • Match path boundaries, so renaming Docs leaves DocsSibling alone.
    • Extend the file-deletion selection cleanup to remove descendant favorites. Ordinary Remove favorite remains exact and keeps child favorites.
    • Preserve the original file operations, callback results/exceptions and null callbacks; no new file moves/deletes are performed by the extension.

    Before / after: same synthetic fixture, native 1080 × 1920 emulator viewport, after the same actual UI rename. Before is the original official release; after is that release patched with Penguin Patches.

    Before After
    Original: favorite still points to Docs/Projects after parent rename Patched: favorite follows Docs2/Projects; neighboring favorites unchanged

    Validation: real single rename, correct favorite navigation and restart persistence; actual multi-select rename dialog; actual deletion of disposable fixture folders preserving unrelated favorites; same-key APK update; 26 native Android assertions, including prefix boundaries, failed callbacks, ordinary unfavorite, original rename execution and unchanged file content. Test/scope details and additional multi-rename screenshot are public.

    Limits: independently tested on internal shared storage only; external SAF/SD/root backends and physical Xiaomi devices remain unverified. Deletion cleanup retains Fossify's existing pre-deletion selection timing, so a later filesystem deletion failure is not transactional and can still leave removed favorites. This does not recover favorites already lost before installing the patch or intercept renames in other apps.

    Release: v1.0.0-dev.3. Input must be the original official 1.6.2 APK. This is an independent workaround, not an upstream fix. Preserve settings/favorites and signing-key recovery before migrating an official-signed installation.

    Update: two available paths

    1. Immediate, optional workaround: Penguin Patches v1.0.0-dev.4, compatible with Morphe and restricted to the original official File Manager 1.6.2 APK.
    2. Proposed permanent upstream fix: The native Kotlin source candidate is now public in my fork: tested branch, source comparison, and Android regression tests. Build, Android Lint and Detekt passed; both source-build Android tests passed, including a real batch rename dialog with a skipped collision, successful rename, nested-favorite update and unchanged file contents. The screenshots above show the APK workaround, not the source build.

    Dependency: batch directory rename needs this separately prepared Commons callback branch (comparison). It preserves the existing constructor and reports each successful old/new path. Commons build/Detekt and the consuming File Manager dialog test passed. File Manager was tested using a temporary local Commons artifact; its currently declared published Commons dependency does not yet expose this API. Commons must be approved and released first, then File Manager must pin that actual version and be retested. No production dependency version is being claimed here.

    These are reviewable fork branches, not submitted upstream PRs or merged fixes. Would the maintainers welcome the focused source fix after triage? I will wait for explicit approval or the required help wanted label before opening an upstream PR, and can split/adapt the commits to the preferred scope.

    Patch retirement follows an actual verified official fixed release, not PR acceptance alone. Already fixed future versions will not be added to the workaround's compatibility list. Physical-device/OEM behavior and the previously listed backend/carrier limits remain unverified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is not workingneeds triageIssue is not yet ready for PR authors to take up

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions