Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/lib/openFolder.js
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ function execOperation(type, action, url, $target, name) {
newName = helpers.fixFilename(newName);
if (!newName) return;
startLoading();
const isNestedPath = newName.split("/").filter(Boolean).length > 1;
let newUrl;

if (action === "new file") {
Expand All @@ -672,6 +673,14 @@ function execOperation(type, action, url, $target, name) {
newUrl = await helpers.createFileStructure(url, newName, false);
}
if (!newUrl) return;

if (isNestedPath) {
openFolder.find(url)?.reload();
await FileList.refresh();
toast(strings.success);
return;
}

newName = Url.basename(newUrl.uri);
if ($target.unclasped) {
if (newUrl.type === "file") {
Expand Down
159 changes: 76 additions & 83 deletions src/utils/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,73 +418,28 @@ export default {
const terminalBasePath = isAcodeTerminalPublicSafUri
? decodeURIComponent(treeSegment.split("::")[0] || "")
: "";

if (isExternalStorageUri) {
baseFolder = decodeURIComponent(currentUri.split("%3A")[1].split("/")[0]);
} else if (
!(isExternalStorageUri || isTermuxUri || isAcodeTerminalPublicSafUri)
) {
// Handle nested paths for regular file:// URIs
const pathParts = pathString.split("/").filter(Boolean);
let currentPath = uri;
let firstCreatedPath = null;
let firstCreatedType = null;

for (let i = 0; i < pathParts.length; i++) {
const isLastPart = i === pathParts.length - 1;
const partName = pathParts[i];
const newPath = Url.join(currentPath, partName);

if (isLastPart && isFile) {
// Create file if it's the last part and we're creating a file
if (!(await fsOperation(newPath).exists())) {
await fsOperation(currentPath).createFile(partName);
if (firstCreatedPath === null) {
firstCreatedPath = newPath;
firstCreatedType = "file";
}
}
} else {
// Create directory for intermediate parts or when creating a folder
if (!(await fsOperation(newPath).exists())) {
await fsOperation(currentPath).createDirectory(partName);
if (firstCreatedPath === null) {
firstCreatedPath = newPath;
firstCreatedType = "folder";
}
}
}
currentPath = newPath;
const getTargetUri = (baseUri, name, index) => {
if (
!(isExternalStorageUri || isTermuxUri || isAcodeTerminalPublicSafUri)
) {
return Url.join(baseUri, name);
}

return {
uri: firstCreatedPath || Url.join(uri, pathParts[0]),
type:
firstCreatedType ||
(isFile && pathParts.length === 1 ? "file" : "folder"),
};
}

for (let i = 0; i < parts.length; i++) {
const isLastElement = i === parts.length - 1;
const name = parts[i];
let fullUri = currentUri;

// Adjust URI for special cases
let fullUri = baseUri;
if (isExternalStorageUri) {
if (!isSpecialCase && i === 0) {
if (!isSpecialCase && index === 0) {
fullUri += `::primary:${baseFolder}/${name}`;
} else {
fullUri += `/${name}`;
}
} else if (isTermuxUri) {
if (!isSpecialCase && i === 0) {
if (!isSpecialCase && index === 0) {
fullUri += `::/data/data/com.termux/files/home/${name}`;
} else {
fullUri += `/${name}`;
}
} else if (isAcodeTerminalPublicSafUri) {
if (!isSpecialCase && i === 0) {
if (!isSpecialCase && index === 0) {
const sanitizedBase = terminalBasePath.endsWith("/")
? `${terminalBasePath}${name}`
: `${terminalBasePath}/${name}`;
Expand All @@ -493,41 +448,79 @@ export default {
fullUri += `/${name}`;
}
}

if (isLastElement && isFile) {
// Create file if it's the last element and isFile is true
if (!(await fsOperation(fullUri).exists())) {
await fsOperation(currentUri).createFile(name);
} else {
return;
}
} else {
// Create directory
if (!(await fsOperation(fullUri).exists())) {
await fsOperation(currentUri).createDirectory(name);
} else {
return;
return fullUri;
};
const getExpectedType = (isLastPart) =>
isLastPart && isFile ? "file" : "folder";
const ensureEntry = async (baseUri, targetUri, name, expectedType) => {
const entries = await fsOperation(baseUri).lsDir();
const existingEntry = entries.find((entry) => entry.name === name);

if (existingEntry) {
const actualType =
existingEntry.isDirectory || existingEntry.isFile === false
? "folder"
: "file";
if (actualType !== expectedType) {
throw new Error(
`${name} already exists as a ${actualType}, expected ${expectedType}.`,
);
}

return {
url: existingEntry.url || targetUri,
created: false,
type: expectedType,
};
}
currentUri = fullUri;

const createdUrl =
expectedType === "file"
? await fsOperation(baseUri).createFile(name)
: await fsOperation(baseUri).createDirectory(name);

return {
url: createdUrl || targetUri,
created: true,
type: expectedType,
};
};
let firstCreatedPath = null;
let firstCreatedType = null;
let firstTargetUri = uri;

if (isExternalStorageUri) {
baseFolder = decodeURIComponent(currentUri.split("%3A")[1].split("/")[0]);
}
let tileType;
if (isFile && parts.length === 1) {
tileType = "file";
} else {
const urlParts = currentUri.split("/");
const pathParts = pathString.split("/");
const pathStartIndex = urlParts.findIndex(
(part) => part === pathParts[0],
if (parts[0]) {
firstTargetUri = getTargetUri(uri, parts[0], 0);
}

for (let i = 0; i < parts.length; i++) {
const isLastElement = i === parts.length - 1;
const name = parts[i];
const targetUri = getTargetUri(currentUri, name, i);
const expectedType = getExpectedType(isLastElement);
const entry = await ensureEntry(
currentUri,
targetUri,
name,
expectedType,
);
if (pathStartIndex !== -1) {
const pathEndIndex = pathStartIndex + pathParts.length;
urlParts.splice(pathStartIndex + 1, pathEndIndex - pathStartIndex - 1);

if (entry.created && firstCreatedPath === null) {
firstCreatedPath = entry.url;
firstCreatedType = expectedType;
}
currentUri = urlParts.join("/");
tileType = "folder";

currentUri = entry.url;
}
return { uri: currentUri, type: tileType };

return {
uri: firstCreatedPath || firstTargetUri,
type:
firstCreatedType || (isFile && parts.length === 1 ? "file" : "folder"),
};
},
formatDownloadCount(downloadCount) {
const units = ["", "K", "M", "B", "T"];
Expand Down