Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion src/lib/acode.js
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ class Acode {
}

get exitAppMessage() {
const numFiles = editorManager.hasUnsavedFiles();
const numFiles = editorManager?.hasUnsavedFiles?.() ?? 0;
if (numFiles) {
return strings["unsaved files close app"];
}
Expand Down
66 changes: 60 additions & 6 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ document.addEventListener("deviceready", onDeviceReady);
document.addEventListener("backbutton", backButtonHandler);
document.addEventListener("menubutton", menuButtonHandler);

async function ensurePermission(permission) {
try {
const granted = await helpers.promisify(system.hasPermission, permission);
if (!granted) {
await helpers.promisify(system.requestPermission, permission);
}
} catch (error) {
logger.log(
"error",
`Failed to request permission ${permission}: ${error.message || error}`,
);
}
}

async function onDeviceReady() {
await initEncodings(); // important to load encodings before anything else

Expand All @@ -112,14 +126,37 @@ async function onDeviceReady() {
dataDirectory,
} = cordova.file;

async function resolveStorageDir(preferred, fallback) {
if (!preferred) return fallback;
const fs = fsOperation(preferred);
if (!fs) return fallback;
try {
await fs.stat();
return preferred;
} catch (error) {
logger.log(
"warn",
`Storage dir unavailable (${preferred}), falling back to ${fallback}: ${error.message || error}`,
);
return fallback;
}
}

window.app = document.body;
window.root = tag.get("#root");
window.addedFolder = addedFolder;
window.editorManager = null;
window.toast = toast;
window.ASSETS_DIRECTORY = Url.join(cordova.file.applicationDirectory, "www");
window.DATA_STORAGE = externalDataDirectory || dataDirectory;
window.CACHE_STORAGE = externalCacheDirectory || cacheDirectory;
window.DATA_STORAGE = await resolveStorageDir(
externalDataDirectory,
dataDirectory,
);
window.CACHE_STORAGE = await resolveStorageDir(
externalCacheDirectory,
cacheDirectory,
);

window.PLUGIN_DIR = Url.join(DATA_STORAGE, "plugins");
window.KEYBINDING_FILE = Url.join(DATA_STORAGE, ".key-bindings.json");
window.log = logger.log.bind(logger);
Expand Down Expand Up @@ -212,9 +249,11 @@ async function onDeviceReady() {
await adRewards.init();
ensureAceCompatApi();

system.requestPermission("android.permission.READ_EXTERNAL_STORAGE");
system.requestPermission("android.permission.WRITE_EXTERNAL_STORAGE");
system.requestPermission("android.permission.POST_NOTIFICATIONS");
if (Number.isInteger(window.ANDROID_SDK_INT) && window.ANDROID_SDK_INT < 33) {
await ensurePermission("android.permission.READ_EXTERNAL_STORAGE");
await ensurePermission("android.permission.WRITE_EXTERNAL_STORAGE");
}
await ensurePermission("android.permission.POST_NOTIFICATIONS");

const { versionCode } = BuildInfo;

Expand All @@ -227,7 +266,22 @@ async function onDeviceReady() {
}

if (!(await fsOperation(PLUGIN_DIR).exists())) {
await fsOperation(DATA_STORAGE).createDirectory("plugins");
try {
await fsOperation(DATA_STORAGE).createDirectory("plugins");
} catch (error) {
logger.log(
"error",
`Failed to create plugins directory, falling back to internal storage: ${error.message || error}`,
);
window.DATA_STORAGE = dataDirectory;
window.CACHE_STORAGE = cacheDirectory;
window.PLUGIN_DIR = Url.join(window.DATA_STORAGE, "plugins");
window.KEYBINDING_FILE = Url.join(
window.DATA_STORAGE,
".key-bindings.json",
);
await fsOperation(window.DATA_STORAGE).createDirectory("plugins");
}
}

localStorage.versionCode = versionCode;
Expand Down
24 changes: 20 additions & 4 deletions www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,25 @@
);
}

function isStorageError(reason) {
if (!reason) return false;
return (
reason.name === "FileError" ||
reason.name === "NotFoundError" ||
reason.name === "SecurityError" ||
(typeof reason.code === "number" && reason.code >= 1 && reason.code <= 12)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Treating every numeric code from 1 through 12 as a storage error is weird, it can be different like dom or cordova plugin errors

);
}

function handleStartupError(event) {
if (!isStartupLoading()) return;
var message = event && event.message ? event.message : "Startup error";
setStartupMessage(
"Acode failed to start. Update Android System WebView or Chrome. " +
message
isStorageError(event && event.error)
? "Acode failed to start: storage is unavailable. Try restarting your device, or clearing the app data. " +
message
: "Acode failed to start. Update Android System WebView or Chrome. " +
message
);
}

Expand All @@ -156,8 +169,11 @@
var message =
reason && reason.message ? reason.message : "Startup promise failed";
setStartupMessage(
"Acode failed to start. Update Android System WebView or Chrome. " +
message
isStorageError(reason)
? "Acode failed to start: storage is unavailable. Try restarting your device, or clearing the app data. " +
message
: "Acode failed to start. Update Android System WebView or Chrome. " +
message
);
}

Expand Down