diff --git a/src/components/terminal/lazyTerminalManager.js b/src/components/terminal/lazyTerminalManager.js new file mode 100644 index 000000000..80316b19c --- /dev/null +++ b/src/components/terminal/lazyTerminalManager.js @@ -0,0 +1,14 @@ +let terminalManager; +let terminalManagerPromise; + +export function getLoadedTerminalManager() { + return terminalManager; +} + +export function loadTerminalManager() { + terminalManagerPromise ??= import("./terminalManager").then((module) => { + terminalManager = module.default; + return terminalManager; + }); + return terminalManagerPromise; +} diff --git a/src/components/terminal/terminalManager.js b/src/components/terminal/terminalManager.js index fb8e1ba8f..5e98f0ceb 100644 --- a/src/components/terminal/terminalManager.js +++ b/src/components/terminal/terminalManager.js @@ -4,6 +4,7 @@ */ import "@xterm/xterm/css/xterm.css"; +import "./terminalTouchSelection.css"; import quickTools from "components/quickTools"; import toast from "components/toast"; import alert from "dialogs/alert"; diff --git a/src/components/terminal/terminalTouchSelection.js b/src/components/terminal/terminalTouchSelection.js index dff0e2b48..0f8e8911e 100644 --- a/src/components/terminal/terminalTouchSelection.js +++ b/src/components/terminal/terminalTouchSelection.js @@ -1,4 +1,3 @@ -import "./terminalTouchSelection.css"; import select from "dialogs/select"; const DEFAULT_MORE_OPTION_ID = "__acode_terminal_select_all__"; diff --git a/src/handlers/intent.js b/src/handlers/intent.js index 5e7335b61..0e0da10d7 100644 --- a/src/handlers/intent.js +++ b/src/handlers/intent.js @@ -1,8 +1,8 @@ import fsOperation from "fileSystem"; import auth from "lib/auth"; import config from "lib/config"; +import { loadStartAdModule } from "lib/lazyAds"; import openFile from "lib/openFile"; -import { hideAd } from "lib/startAd"; import helpers from "utils/helpers"; const handlers = []; @@ -53,6 +53,7 @@ export default async function HandleIntent(intent = {}) { try { const user = await auth.getLoggedInUser(true); if (user.acode_pro) { + const { hideAd } = await loadStartAdModule(); hideAd(); config.HAS_PRO = true; const settings = document.querySelector( diff --git a/src/handlers/keyboard.js b/src/handlers/keyboard.js index 32cbb72da..9bec2e571 100644 --- a/src/handlers/keyboard.js +++ b/src/handlers/keyboard.js @@ -1,4 +1,4 @@ -import { bannerAd } from "lib/startAd"; +import { getLoadedStartAdModule } from "lib/lazyAds"; import { getSystemConfiguration, HARDKEYBOARDHIDDEN_NO, @@ -212,6 +212,7 @@ function focusBlurEditor(keyboardHidden) { * @param {boolean} keyboardHidden */ function toggleBannerAd(keyboardHidden) { + const { bannerAd } = getLoadedStartAdModule() || {}; const bannerIsActive = !!bannerAd?.active; if ( diff --git a/src/lib/acode.js b/src/lib/acode.js index da96ae52e..5e949bbda 100644 --- a/src/lib/acode.js +++ b/src/lib/acode.js @@ -34,7 +34,11 @@ import Page from "components/page"; import palette from "components/palette"; import settingsPage from "components/settingsPage"; import SideButton from "components/sideButton"; -import { TerminalManager, TerminalThemeManager } from "components/terminal"; +import { + getLoadedTerminalManager, + loadTerminalManager, +} from "components/terminal/lazyTerminalManager"; +import TerminalThemeManager from "components/terminal/terminalThemeManager"; import toast from "components/toast"; import tutorial from "components/tutorial"; import alert from "dialogs/alert"; @@ -66,7 +70,6 @@ import openFolder, { addedFolder } from "lib/openFolder"; import projects from "lib/projects"; import selectionMenu from "lib/selectionMenu"; import appSettings from "lib/settings"; -import FileBrowser from "pages/fileBrowser"; import formatterSettings from "settings/formatterSettings"; import ThemeBuilder from "theme/builder"; import themes from "theme/list"; @@ -77,6 +80,34 @@ import KeyboardEvent from "utils/keyboardEvent"; import Url from "utils/Url"; import config from "./config"; +let fileBrowserPromise; + +function loadFileBrowser() { + fileBrowserPromise ??= import("pages/fileBrowser").then( + (module) => module.default, + ); + return fileBrowserPromise; +} + +function createLazyFileBrowser() { + const FileBrowser = (...args) => + loadFileBrowser().then((module) => module(...args)); + + for (const method of [ + "openFile", + "openFileError", + "openFolder", + "openFolderError", + "open", + "openError", + ]) { + FileBrowser[method] = (...args) => + loadFileBrowser().then((module) => module[method](...args)); + } + + return FileBrowser; +} + class Acode { #modules = {}; #pluginsInit = {}; @@ -281,20 +312,26 @@ class Acode { }; const terminalTouchSelectionMoreOptions = { - add: (option) => TerminalManager.addTouchSelectionMoreOption(option), - remove: (id) => TerminalManager.removeTouchSelectionMoreOption(id), - list: () => TerminalManager.getTouchSelectionMoreOptions(), + add: async (option) => + (await loadTerminalManager()).addTouchSelectionMoreOption(option), + remove: async (id) => + (await loadTerminalManager()).removeTouchSelectionMoreOption(id), + list: () => + getLoadedTerminalManager()?.getTouchSelectionMoreOptions() || [], }; const terminalModule = { - create: (options) => TerminalManager.createTerminal(options), - createLocal: (options) => TerminalManager.createLocalTerminal(options), - createServer: (options) => TerminalManager.createServerTerminal(options), - get: (id) => TerminalManager.getTerminal(id), - getAll: () => TerminalManager.getAllTerminals(), + create: async (options) => + (await loadTerminalManager()).createTerminal(options), + createLocal: async (options) => + (await loadTerminalManager()).createLocalTerminal(options), + createServer: async (options) => + (await loadTerminalManager()).createServerTerminal(options), + get: (id) => getLoadedTerminalManager()?.getTerminal(id) || null, + getAll: () => getLoadedTerminalManager()?.getAllTerminals() || [], write: (id, data) => this.#secureTerminalWrite(id, data), - clear: (id) => TerminalManager.clearTerminal(id), - close: (id) => TerminalManager.closeTerminal(id), + clear: async (id) => (await loadTerminalManager()).clearTerminal(id), + close: async (id) => (await loadTerminalManager()).closeTerminal(id), moreOptions: terminalTouchSelectionMoreOptions, touchSelection: { moreOptions: terminalTouchSelectionMoreOptions, @@ -389,7 +426,7 @@ class Acode { this.define("multiPrompt", multiPrompt); this.define("addedfolder", addedFolder); this.define("contextMenu", Contextmenu); - this.define("fileBrowser", FileBrowser); + this.define("fileBrowser", createLazyFileBrowser()); this.define("fsOperation", fsOperation); this.define("keyboard", keyboardHandler); this.define("windowResize", windowResize); @@ -508,7 +545,9 @@ class Acode { } // If all security checks pass, proceed with writing - return TerminalManager.writeToTerminal(id, data); + return loadTerminalManager().then((TerminalManager) => + TerminalManager.writeToTerminal(id, data), + ); } /** diff --git a/src/lib/canSaveFile.js b/src/lib/canSaveFile.js new file mode 100644 index 000000000..e875688b0 --- /dev/null +++ b/src/lib/canSaveFile.js @@ -0,0 +1,9 @@ +export function canSaveFile(file = editorManager.activeFile) { + return ( + file?.type === "editor" && + typeof file.save === "function" && + typeof file.saveAs === "function" + ); +} + +export default canSaveFile; diff --git a/src/lib/commands.js b/src/lib/commands.js index 9c7aa21b6..1e2703b14 100644 --- a/src/lib/commands.js +++ b/src/lib/commands.js @@ -1,39 +1,18 @@ import fsOperation from "fileSystem"; -import { selectAll } from "@codemirror/commands"; -import Sidebar from "components/sidebar"; -import { TerminalManager } from "components/terminal"; -import color from "dialogs/color"; import confirm from "dialogs/confirm"; import prompt from "dialogs/prompt"; import select from "dialogs/select"; -import actions from "handlers/quickTools"; import recents from "lib/recents"; -import About from "pages/about"; -import FileBrowser from "pages/fileBrowser"; -import plugins from "pages/plugins"; -import Problems from "pages/problems/problems"; -import openWelcomeTab from "pages/welcome/welcome"; -import changeEncoding from "palettes/changeEncoding"; -import changeMode from "palettes/changeMode"; -import changeTheme from "palettes/changeTheme"; -import commandPalette from "palettes/commandPalette"; -import findFile from "palettes/findFile"; -import browser from "plugins/browser"; -import help from "settings/helpSettings"; -import mainSettings from "settings/mainSettings"; -import { runAllTests } from "test/tester"; -import { getColorRange } from "utils/color/regex"; import helpers from "utils/helpers"; import Url from "utils/Url"; +import { canSaveFile } from "./canSaveFile"; import checkFiles from "./checkFiles"; import config from "./config"; import EditorFile from "./editorFile"; -import openFile from "./openFile"; -import openFolder from "./openFolder"; -import run from "./run"; import saveState from "./saveState"; import appSettings from "./settings"; -import showFileInfo from "./showFileInfo"; + +export { canSaveFile }; function getTabCloseSelectionOptions() { return { @@ -65,14 +44,6 @@ function resolveReferenceFile(referenceFile) { return referenceFile; } -export function canSaveFile(file = editorManager.activeFile) { - return ( - file?.type === "editor" && - typeof file.save === "function" && - typeof file.saveAs === "function" - ); -} - function getTabsRelativeToFile(side, referenceFile) { const { files } = editorManager; const file = resolveReferenceFile(referenceFile); @@ -140,6 +111,7 @@ async function closeTabs(files, options = {}) { export default { async "run-tests"() { + const { runAllTests } = await import("test/tester"); await runAllTests(); }, async "close-all-tabs"() { @@ -180,14 +152,16 @@ export default { "toggle-pin-tab"(referenceFile) { resolveReferenceFile(referenceFile)?.togglePinned?.(); }, - console() { + async console() { + const { default: run } = await import("./run"); run(true, "inapp"); }, "check-files"() { if (!appSettings.value.checkFiles) return; checkFiles(); }, - "command-palette"() { + async "command-palette"() { + const { default: commandPalette } = await import("palettes/commandPalette"); commandPalette(); }, "disable-fullscreen"() { @@ -198,7 +172,8 @@ export default { app.classList.add("fullscreen-mode"); this["resize-editor"](); }, - encoding() { + async encoding() { + const { default: changeEncoding } = await import("palettes/changeEncoding"); changeEncoding(); }, exit() { @@ -207,18 +182,22 @@ export default { "edit-with"() { editorManager.activeFile.editWith(); }, - "find-file"() { + async "find-file"() { + const { default: findFile } = await import("palettes/findFile"); findFile(); }, - files() { + async files() { + const { default: FileBrowser } = await import("pages/fileBrowser"); FileBrowser("both", strings["file browser"]) .then(FileBrowser.open) .catch(FileBrowser.openError); }, - find() { + async find() { + const { default: actions } = await import("handlers/quickTools"); actions("search"); }, - "file-info"(url) { + async "file-info"(url) { + const { default: showFileInfo } = await import("./showFileInfo"); showFileInfo(url); }, async goto() { @@ -256,30 +235,50 @@ export default { editorManager.files[fileIndex].makeActive(); }, - open(page) { + async open(page) { switch (page) { case "settings": - mainSettings(); + { + const { default: mainSettings } = await import( + "settings/mainSettings" + ); + mainSettings(); + } break; case "help": - help(); + { + const { default: help } = await import("settings/helpSettings"); + help(); + } break; case "problems": - Problems(); + { + const { default: Problems } = await import("pages/problems/problems"); + Problems(); + } break; case "plugins": - plugins(); + { + const { default: plugins } = await import("pages/plugins"); + plugins(); + } break; case "file_browser": - FileBrowser(); + { + const { default: FileBrowser } = await import("pages/fileBrowser"); + FileBrowser(); + } break; case "about": - About(); + { + const { default: About } = await import("pages/about"); + About(); + } break; default: @@ -290,13 +289,15 @@ export default { "open-with"() { editorManager.activeFile.openWith(); }, - "open-file"() { + async "open-file"() { + const { default: FileBrowser } = await import("pages/fileBrowser"); editorManager.editor.contentDOM.blur(); FileBrowser("file") .then(FileBrowser.openFile) .catch(FileBrowser.openFileError); }, - "open-folder"() { + async "open-folder"() { + const { default: FileBrowser } = await import("pages/fileBrowser"); editorManager.editor.contentDOM.blur(); FileBrowser("folder") .then(FileBrowser.openFolder) @@ -315,7 +316,11 @@ export default { const file = editorManager.activeFile; file.editable = !file.editable; }, - recent() { + async recent() { + const [{ default: openFile }, { default: openFolder }] = await Promise.all([ + import("./openFile"), + import("./openFolder"), + ]); recents.select().then((res) => { const { type } = res; if (helpers.isFile(type)) { @@ -338,7 +343,8 @@ export default { // TODO : Codemirror //editorManager.editor.resize(true); }, - "open-inapp-browser"(url) { + async "open-inapp-browser"(url) { + const { default: browser } = await import("plugins/browser"); browser.open(url); }, run() { @@ -433,20 +439,24 @@ export default { helpers.error(error); } }, - syntax() { + async syntax() { + const { default: changeMode } = await import("palettes/changeMode"); changeMode(); }, - "change-app-theme"() { + async "change-app-theme"() { + const { default: changeTheme } = await import("palettes/changeTheme"); changeTheme("app"); }, - "change-editor-theme"() { + async "change-editor-theme"() { + const { default: changeTheme } = await import("palettes/changeTheme"); changeTheme("editor"); }, "toggle-fullscreen"() { app.classList.toggle("fullscreen-mode"); this["resize-editor"](); }, - "toggle-sidebar"() { + async "toggle-sidebar"() { + const { default: Sidebar } = await import("components/sidebar"); Sidebar.toggle(); }, "toggle-menu"() { @@ -456,6 +466,10 @@ export default { tag.get("[action=toggle-edit-menu")?.click(); }, async "insert-color"() { + const [{ default: color }, { getColorRange }] = await Promise.all([ + import("dialogs/color"), + import("utils/color/regex"), + ]); const { editor } = editorManager; const range = getColorRange(); let defaultColor = ""; @@ -498,7 +512,8 @@ export default { paste() { editorManager.editor.execCommand("paste"); }, - "select-all"() { + async "select-all"() { + const { selectAll } = await import("@codemirror/commands"); const { editor } = editorManager; selectAll(editor); }, @@ -539,6 +554,7 @@ export default { file.uri = newUri; file.filename = newname; + const { default: openFolder } = await import("./openFolder"); openFolder.renameItem(uri, newUri, newname); toast(strings["file renamed"]); } catch (err) { @@ -564,7 +580,8 @@ export default { }); editorManager.activeFile.eol = eol; }, - "open-log-file"() { + async "open-log-file"() { + const { default: openFile } = await import("./openFile"); openFile(Url.join(DATA_STORAGE, config.LOG_FILE_NAME)); }, "copy-device-info"() { @@ -637,6 +654,10 @@ Additional Info: }, async "new-terminal"() { try { + const { loadTerminalManager } = await import( + "components/terminal/lazyTerminalManager" + ); + const TerminalManager = await loadTerminalManager(); await TerminalManager.createServerTerminal(); } catch (error) { console.error("Failed to create terminal:", error); @@ -649,7 +670,8 @@ Additional Info: ); RunningProcesses(); }, - welcome() { + async welcome() { + const { default: openWelcomeTab } = await import("pages/welcome"); openWelcomeTab(); }, async "toggle-inspector"() { diff --git a/src/lib/editorFile.js b/src/lib/editorFile.js index 9c89af17b..d36b8cfc8 100644 --- a/src/lib/editorFile.js +++ b/src/lib/editorFile.js @@ -451,7 +451,7 @@ export default class EditorFile { let container; let shadow; - if (this.#type === "terminal") { + if (this.#type === "terminal" || this.#type === "welcome") { container = tag("div", { className: "tab-page-container", }); diff --git a/src/lib/lazyAds.js b/src/lib/lazyAds.js new file mode 100644 index 000000000..fbd8d9e03 --- /dev/null +++ b/src/lib/lazyAds.js @@ -0,0 +1,28 @@ +let adRewards; +let adRewardsPromise; +let startAdModule; +let startAdModulePromise; + +export function getLoadedAdRewards() { + return adRewards; +} + +export function loadAdRewards() { + adRewardsPromise ??= import("lib/adRewards").then((module) => { + adRewards = module.default; + return adRewards; + }); + return adRewardsPromise; +} + +export function getLoadedStartAdModule() { + return startAdModule; +} + +export function loadStartAdModule() { + startAdModulePromise ??= import("lib/startAd").then((module) => { + startAdModule = module; + return startAdModule; + }); + return startAdModulePromise; +} diff --git a/src/lib/openFolder.js b/src/lib/openFolder.js index 6b96c74f9..1bfef45a9 100644 --- a/src/lib/openFolder.js +++ b/src/lib/openFolder.js @@ -3,7 +3,6 @@ import sidebarApps from "sidebarApps"; import collapsableList from "components/collapsableList"; import FileTree from "components/fileTree"; import Sidebar from "components/sidebar"; -import { TerminalManager } from "components/terminal"; import tile from "components/tile"; import toast from "components/toast"; import alert from "dialogs/alert"; @@ -11,7 +10,6 @@ import confirm from "dialogs/confirm"; import prompt from "dialogs/prompt"; import select from "dialogs/select"; import escapeStringRegexp from "escape-string-regexp"; -import FileBrowser from "pages/fileBrowser"; import helpers from "utils/helpers"; import Path from "utils/Path"; import Uri from "utils/Uri"; @@ -539,6 +537,10 @@ function execOperation(type, action, url, $target, name) { async function openInTerminal() { try { + const { loadTerminalManager } = await import( + "components/terminal/lazyTerminalManager" + ); + const TerminalManager = await loadTerminalManager(); const prootPath = convertToProotPath(url); const terminal = await TerminalManager.createTerminal({ name: `Terminal - ${name}`, @@ -897,6 +899,7 @@ function execOperation(type, action, url, $target, name) { async function insertFile() { startLoading(); try { + const { default: FileBrowser } = await import("pages/fileBrowser"); const file = await FileBrowser("file", strings["insert file"]); const sourceFs = fsOperation(file.url); const data = await sourceFs.readFile(); @@ -923,6 +926,7 @@ function execOperation(type, action, url, $target, name) { } async function open() { + const { default: FileBrowser } = await import("pages/fileBrowser"); FileBrowser.openFolder({ url, name, diff --git a/src/lib/prettierFormatter.js b/src/lib/prettierFormatter.js index 4b93fa0f6..f608da8d1 100644 --- a/src/lib/prettierFormatter.js +++ b/src/lib/prettierFormatter.js @@ -2,15 +2,6 @@ import fsOperation from "fileSystem"; import { parse } from "acorn"; import toast from "components/toast"; import appSettings from "lib/settings"; -import prettierPluginBabel from "prettier/plugins/babel"; -import prettierPluginEstree from "prettier/plugins/estree"; -import prettierPluginGraphql from "prettier/plugins/graphql"; -import prettierPluginHtml from "prettier/plugins/html"; -import prettierPluginMarkdown from "prettier/plugins/markdown"; -import prettierPluginPostcss from "prettier/plugins/postcss"; -import prettierPluginTypescript from "prettier/plugins/typescript"; -import prettierPluginYaml from "prettier/plugins/yaml"; -import prettier from "prettier/standalone"; import helpers from "utils/helpers"; import Url from "utils/Url"; @@ -33,16 +24,7 @@ const CONFIG_FILENAMES = [ "prettier.config.cjs", "prettier.config.mjs", ]; -const PRETTIER_PLUGINS = [ - prettierPluginEstree, - prettierPluginBabel, - prettierPluginHtml, - prettierPluginMarkdown, - prettierPluginPostcss, - prettierPluginTypescript, - prettierPluginYaml, - prettierPluginGraphql, -]; +let prettierModulesPromise; /** * Supported parser mapping keyed by CodeMirror mode name @@ -129,11 +111,12 @@ async function formatActiveFileWithPrettier() { const source = doc.toString(); const filepath = file.uri || file.filename || ""; try { + const { prettier, plugins } = await loadPrettierModules(); const config = await resolvePrettierConfig(file); const formatted = await prettier.format(source, { ...config, parser, - plugins: PRETTIER_PLUGINS, + plugins, filepath, overrideEditorconfig: true, }); @@ -155,6 +138,46 @@ async function formatActiveFileWithPrettier() { } } +function loadPrettierModules() { + prettierModulesPromise ??= Promise.all([ + import("prettier/standalone"), + import("prettier/plugins/estree"), + import("prettier/plugins/babel"), + import("prettier/plugins/html"), + import("prettier/plugins/markdown"), + import("prettier/plugins/postcss"), + import("prettier/plugins/typescript"), + import("prettier/plugins/yaml"), + import("prettier/plugins/graphql"), + ]).then( + ([ + { default: prettier }, + { default: prettierPluginEstree }, + { default: prettierPluginBabel }, + { default: prettierPluginHtml }, + { default: prettierPluginMarkdown }, + { default: prettierPluginPostcss }, + { default: prettierPluginTypescript }, + { default: prettierPluginYaml }, + { default: prettierPluginGraphql }, + ]) => ({ + prettier, + plugins: [ + prettierPluginEstree, + prettierPluginBabel, + prettierPluginHtml, + prettierPluginMarkdown, + prettierPluginPostcss, + prettierPluginTypescript, + prettierPluginYaml, + prettierPluginGraphql, + ], + }), + ); + + return prettierModulesPromise; +} + function getParserForMode(modeName) { if (MODE_TO_PARSER[modeName]) return MODE_TO_PARSER[modeName]; if (modeName.includes("javascript")) return "babel"; diff --git a/src/lib/saveFile.js b/src/lib/saveFile.js index 44d067fcc..72c454484 100644 --- a/src/lib/saveFile.js +++ b/src/lib/saveFile.js @@ -2,7 +2,6 @@ import fsOperation from "fileSystem"; import prompt from "dialogs/prompt"; import select from "dialogs/select"; import recents from "lib/recents"; -import FileBrowser from "pages/fileBrowser"; import helpers from "utils/helpers"; import Url from "utils/Url"; import config from "./config"; @@ -162,6 +161,7 @@ async function saveFile(file, isSaveAs = false) { } async function selectFolder() { + const { default: FileBrowser } = await import("pages/fileBrowser"); const dir = await FileBrowser( "folder", strings[`save file${isSaveAs ? " as" : ""}`], diff --git a/src/main.js b/src/main.js index 05ef4c067..feb96f337 100644 --- a/src/main.js +++ b/src/main.js @@ -24,7 +24,6 @@ import { import Contextmenu from "components/contextmenu"; import { hasConnectedServers } from "components/lspInfoDialog"; import Sidebar from "components/sidebar"; -import { TerminalManager } from "components/terminal"; import tile from "components/tile"; import toast from "components/toast"; import tutorial from "components/tutorial"; @@ -35,18 +34,17 @@ import quickToolsInit from "handlers/quickToolsInit"; import windowResize from "handlers/windowResize"; import acode from "lib/acode"; import actionStack from "lib/actionStack"; -import adRewards from "lib/adRewards"; import ajax from "lib/ajax"; import applySettings from "lib/applySettings"; +import { canSaveFile } from "lib/canSaveFile"; import checkFiles from "lib/checkFiles"; -import checkPluginsUpdate from "lib/checkPluginsUpdate"; -import { canSaveFile } from "lib/commands"; import config from "lib/config"; import EditorFile from "lib/editorFile"; import EditorManager from "lib/editorManager"; import { initFileList } from "lib/fileList"; import fonts from "lib/fonts"; import lang from "lib/lang"; +import { loadAdRewards, loadStartAdModule } from "lib/lazyAds"; import loadPlugins from "lib/loadPlugins"; import Logger from "lib/logger"; import notificationManager from "lib/notificationManager"; @@ -54,10 +52,7 @@ import openFolder, { addedFolder } from "lib/openFolder"; import { registerPrettierFormatter } from "lib/prettierFormatter"; import restoreFiles from "lib/restoreFiles"; import settings from "lib/settings"; -import startAd, { hideAd } from "lib/startAd"; import mustache from "mustache"; -import plugins from "pages/plugins"; -import openWelcomeTab from "pages/welcome"; import otherSettings from "settings/appSettings"; import themes from "theme/list"; import { initHighlighting } from "utils/codeHighlight"; @@ -209,7 +204,6 @@ async function onDeviceReady() { return true; })(); window.acode = acode; - await adRewards.init(); ensureAceCompatApi(); system.requestPermission("android.permission.READ_EXTERNAL_STORAGE"); @@ -286,26 +280,34 @@ async function onDeviceReady() { document.body.removeAttribute("data-small-msg"); app.classList.remove("loading", "splash"); - // load plugins - try { - await loadPlugins(); - // Ensure at least one sidebar app is active after all plugins are loaded - // This handles cases where the stored section was from an uninstalled plugin - sidebarApps.ensureActiveApp(); + requestAnimationFrame(() => { + initAdRewards(); + }); - // Re-emit events for active file after plugins are loaded - const { activeFile } = editorManager; - if (activeFile?.uri) { - // Re-emit file-loaded event - editorManager.emit("file-loaded", activeFile); - // Re-emit switch-file event - editorManager.emit("switch-file", activeFile); + await restoreTerminalSessions(); + + setTimeout(async () => { + try { + await loadPlugins(); + + setTimeout(() => { + // Ensure at least one sidebar app is active after all plugins are loaded. + sidebarApps.ensureActiveApp(); + + // Re-emit events for active file after plugins are loaded. + const { activeFile } = editorManager; + if (activeFile?.uri) { + editorManager.emit("file-loaded", activeFile); + editorManager.emit("switch-file", activeFile); + } + }, 0); + } catch (error) { + window.log("error", "Failed to load plugins!"); + window.log("error", error); + toast("Failed to load plugins!"); } - } catch (error) { - window.log("error", "Failed to load plugins!"); - window.log("error", error); - toast("Failed to load plugins!"); - } + }, 0); + applySettings.afterRender(); // Check login status before emitting events @@ -322,87 +324,11 @@ async function onDeviceReady() { } fetchPromotions(); - startAd(); + startAds(); + checkForAppUpdates(); + checkForPluginUpdates(); }, 500); } - - await promptUpdateCheckConsent(); - - // Check for app updates - if (settings.value.checkForAppUpdates && navigator.onLine) { - cordova.plugin.http.sendRequest( - "https://api.github.com/repos/Acode-Foundation/Acode/releases/latest", - { - method: "GET", - responseType: "json", - }, - (response) => { - const release = response.data; - // assuming version is in format v1.2.3 - const versionFormat = /^v?(\d+(?:\.\d+)*)/; - const latestVersion = release.tag_name - .match(versionFormat)?.[1] - .split(".") - .map(Number); - const currentVersion = BuildInfo.version - .match(versionFormat)?.[1] - .split(".") - .map(Number); - if (!(latestVersion && currentVersion)) { - window.log( - "error", - "Failed to parse version while checking for updates.", - ); - return; - } - - let hasUpdate = false; - for (let i = 0; i < latestVersion.length; i++) { - const latest = latestVersion[i]; - const current = currentVersion[i] || 0; - if (latest > current) { - hasUpdate = true; - break; - } else if (latest < current) { - break; - } - } - - if (hasUpdate) { - acode.pushNotification( - "Update Available", - `Acode ${release.tag_name} is now available! Click here to checkout.`, - { - icon: "update", - type: "warning", - action: () => { - system.openInBrowser(release.html_url); - }, - }, - ); - } - }, - (err) => { - window.log("error", "Failed to check for updates"); - window.log("error", err); - }, - ); - } - checkPluginsUpdate() - .then((updates) => { - if (!updates.length) return; - acode.pushNotification( - "Plugin Updates", - `${updates.length} plugin${updates.length > 1 ? "s" : ""} ${updates.length > 1 ? "have" : "has"} new version${updates.length > 1 ? "s" : ""} available.`, - { - icon: "extension", - action: () => { - plugins(updates); - }, - }, - ); - }) - .catch(console.error); } async function onLogin() { @@ -413,6 +339,7 @@ async function onLogin() { config.HAS_PRO = true; } if (config.HAS_PRO) { + const { hideAd } = await loadStartAdModule(); hideAd(true); } } catch (error) { @@ -420,6 +347,15 @@ async function onLogin() { } } +async function initAdRewards() { + try { + const adRewards = await loadAdRewards(); + await adRewards.init(); + } catch (error) { + console.error("Failed to initialize ad rewards:", error); + } +} + async function fetchPromotions() { try { const res = await fetch(`${config.API_BASE}/promotions`); @@ -434,6 +370,115 @@ async function fetchPromotions() { } } +async function startAds() { + try { + const { default: startAd } = await loadStartAdModule(); + startAd(); + } catch (error) { + console.error("Failed to start ads:", error); + } +} + +async function restoreTerminalSessions() { + try { + const { loadTerminalManager } = await import( + "components/terminal/lazyTerminalManager" + ); + const TerminalManager = await loadTerminalManager(); + await TerminalManager.restorePersistedSessions(); + } catch (error) { + console.error("Terminal restoration failed:", error); + } +} + +async function checkForAppUpdates() { + await promptUpdateCheckConsent(); + + if (!settings.value.checkForAppUpdates || !navigator.onLine) return; + + cordova.plugin.http.sendRequest( + "https://api.github.com/repos/Acode-Foundation/Acode/releases/latest", + { + method: "GET", + responseType: "json", + }, + (response) => { + const release = response.data; + // assuming version is in format v1.2.3 + const versionFormat = /^v?(\d+(?:\.\d+)*)/; + const latestVersion = release.tag_name + .match(versionFormat)?.[1] + .split(".") + .map(Number); + const currentVersion = BuildInfo.version + .match(versionFormat)?.[1] + .split(".") + .map(Number); + if (!(latestVersion && currentVersion)) { + window.log( + "error", + "Failed to parse version while checking for updates.", + ); + return; + } + + let hasUpdate = false; + for (let i = 0; i < latestVersion.length; i++) { + const latest = latestVersion[i]; + const current = currentVersion[i] || 0; + if (latest > current) { + hasUpdate = true; + break; + } + if (latest < current) { + break; + } + } + + if (hasUpdate) { + acode.pushNotification( + "Update Available", + `Acode ${release.tag_name} is now available! Click here to checkout.`, + { + icon: "update", + type: "warning", + action: () => { + system.openInBrowser(release.html_url); + }, + }, + ); + } + }, + (err) => { + window.log("error", "Failed to check for updates"); + window.log("error", err); + }, + ); +} + +async function checkForPluginUpdates() { + try { + const { default: checkPluginsUpdate } = await import( + "lib/checkPluginsUpdate" + ); + const updates = await checkPluginsUpdate(); + if (!updates.length) return; + acode.pushNotification( + "Plugin Updates", + `${updates.length} plugin${updates.length > 1 ? "s" : ""} ${updates.length > 1 ? "have" : "has"} new version${updates.length > 1 ? "s" : ""} available.`, + { + icon: "extension", + action: async () => { + const { default: plugins } = await import("pages/plugins"); + plugins(updates); + }, + }, + ); + } catch (error) { + console.error(error); + } +} + async function setDebugInfo() { const { version, versionCode } = BuildInfo; @@ -622,6 +667,7 @@ async function loadApp() { window.log("info", "Started app and its services..."); if (!files.length) { + const { default: openWelcomeTab } = await import("pages/welcome"); openWelcomeTab(); } @@ -665,10 +711,6 @@ async function loadApp() { initFileList(); - TerminalManager.restorePersistedSessions().catch((error) => { - console.error("Terminal restoration failed:", error); - }); - /** * * @param {MouseEvent} e @@ -690,7 +732,11 @@ async function loadApp() { // if (!$editMenuToggler.isConnected) { // $header.insertBefore($editMenuToggler, $header.lastChild); // } - if (activeFile?.type === "page" || activeFile?.type === "terminal") { + if ( + activeFile?.type === "page" || + activeFile?.type === "terminal" || + activeFile?.type === "welcome" + ) { $editMenuToggler.remove(); } else { if (!$editMenuToggler.isConnected) { @@ -874,8 +920,13 @@ async function pauseHandler() { acode?.exec("save-state"); } -function resumeHandler() { - adRewards.handleResume(); +async function resumeHandler() { + try { + const adRewards = await loadAdRewards(); + adRewards.handleResume(); + } catch (error) { + console.error("Failed to resume ad rewards:", error); + } if (!settings.value.checkFiles) return; checkFiles(); } diff --git a/src/pages/welcome/welcome.js b/src/pages/welcome/welcome.js index 0ede6cf44..a20a18fd6 100644 --- a/src/pages/welcome/welcome.js +++ b/src/pages/welcome/welcome.js @@ -20,7 +20,7 @@ export default function openWelcomeTab() { const welcomeFile = new EditorFile("Welcome", { id: "welcome-tab", render: true, - type: "page", + type: "welcome", content: welcomeContent, tabIcon: "icon acode", hideQuickTools: true, diff --git a/src/theme/list.js b/src/theme/list.js index 1b53ee3ba..652a0cfa1 100644 --- a/src/theme/list.js +++ b/src/theme/list.js @@ -4,7 +4,6 @@ import color from "utils/color"; import Url from "utils/Url"; import fonts from "../lib/fonts"; import settings from "../lib/settings"; -import { updateActiveTerminals } from "../settings/terminalSettings"; import ThemeBuilder from "./builder"; import themes, { updateSystemTheme } from "./preInstalled"; @@ -124,6 +123,9 @@ export async function apply(id, init) { if (init && firstTime && theme.preferredTerminalTheme) { if (editorManager != null) { + const { updateActiveTerminals } = await import( + "../settings/terminalSettings" + ); updateActiveTerminals("theme", theme.preferredTerminalTheme); } } diff --git a/src/utils/helpers.js b/src/utils/helpers.js index 749328c12..2372effcf 100644 --- a/src/utils/helpers.js +++ b/src/utils/helpers.js @@ -2,9 +2,12 @@ import fsOperation from "fileSystem"; import { getModeForPath as getCMModeForPath } from "cm/modelist"; import alert from "dialogs/alert"; import escapeStringRegexp from "escape-string-regexp"; -import adRewards from "lib/adRewards"; import config from "lib/config"; -import { bannerAd, interstitialAd } from "lib/startAd"; +import { + getLoadedAdRewards, + getLoadedStartAdModule, + loadStartAdModule, +} from "lib/lazyAds"; import { isBinaryFile } from "./binaryExtensions"; import path from "./Path"; import Uri from "./Uri"; @@ -290,10 +293,11 @@ export default { editorManager.emit("update", "file-delete"); }, canShowAds() { - return Boolean(!config.HAS_PRO && adRewards.canShowAds()); + return Boolean(!config.HAS_PRO && getLoadedAdRewards()?.canShowAds()); }, async showInterstitialIfReady() { if (!this.canShowAds()) return false; + const { interstitialAd } = await loadStartAdModule(); if ( typeof interstitialAd?.isLoaded === "function" && typeof interstitialAd?.show === "function" && @@ -310,6 +314,7 @@ export default { showAd() { if (!this.canShowAds()) return; if (innerHeight * devicePixelRatio <= 600) return; + const { bannerAd } = getLoadedStartAdModule() || {}; if (!bannerAd || typeof bannerAd.show !== "function") return; const $page = tag.getAll("wc-page:not(#root)").pop();