diff --git a/actions/src/main/java/com/itsaky/androidide/actions/internal/DefaultActionsRegistry.kt b/actions/src/main/java/com/itsaky/androidide/actions/internal/DefaultActionsRegistry.kt index 1b3c18da1..05e3d9a9e 100644 --- a/actions/src/main/java/com/itsaky/androidide/actions/internal/DefaultActionsRegistry.kt +++ b/actions/src/main/java/com/itsaky/androidide/actions/internal/DefaultActionsRegistry.kt @@ -16,7 +16,6 @@ */ package com.itsaky.androidide.actions.internal -import android.content.Context import android.view.Menu import android.view.MenuItem import com.google.auto.service.AutoService @@ -167,24 +166,24 @@ class DefaultActionsRegistry : ActionsRegistry() { item.icon = action.icon?.apply { colorFilter = action.createColorFilter(data) + alpha = if (action.enabled) 255 else 76 } - if (item.icon != null) { - item.icon!!.alpha = if (action.enabled) 255 else 76 - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) - } else { - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) - } - - val showAsAction = action.getShowAsActionFlags(data) - if (showAsAction != -1) { - item.setShowAsAction(showAsAction) + var showAsAction = action.getShowAsActionFlags(data) + if (showAsAction == -1) { + showAsAction = if (action.icon != null) { + MenuItem.SHOW_AS_ACTION_IF_ROOM + } else { + MenuItem.SHOW_AS_ACTION_NEVER + } } if (!action.enabled) { - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) + showAsAction = MenuItem.SHOW_AS_ACTION_NEVER } + item.setShowAsAction(showAsAction) + action.createActionView(data)?.let { item.actionView = it } if (action !is ActionMenu) { @@ -195,7 +194,7 @@ class DefaultActionsRegistry : ActionsRegistry() { } /** Executes the given action item with the given */ - fun executeAction(action: ActionItem, data: ActionData) : Job { + fun executeAction(action: ActionItem, data: ActionData): Job { val onMainThread = action.requiresUIThread val context = if (onMainThread) Dispatchers.Main.immediate else Dispatchers.Default return actionsCoroutineScope.launch(context) { diff --git a/app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt b/app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt index ef5513193..c26706b7f 100644 --- a/app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt +++ b/app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt @@ -134,8 +134,12 @@ abstract class BaseEditorActivity : } } + private var optionsMenuInvalidator: Runnable? = null + companion object { + private const val OPTIONS_MENU_INVALIDATION_DELAY = 150L + const val EDITOR_CONTAINER_SCALE_FACTOR = 0.87f const val KEY_BOTTOM_SHEET_SHOWN = "editor_bottomSheetShown" const val KEY_PROJECT_PATH = "saved_projectPath" @@ -154,6 +158,12 @@ abstract class BaseEditorActivity : internal abstract fun doConfirmProjectClose() protected open fun preDestroy() { + optionsMenuInvalidator?.also { + ThreadUtils.getMainHandler().removeCallbacks(it) + } + + optionsMenuInvalidator = null + installationCallback?.destroy() installationCallback = null @@ -199,6 +209,8 @@ abstract class BaseEditorActivity : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + this.optionsMenuInvalidator = Runnable { super.invalidateOptionsMenu() } + registerLanguageServers() if (savedInstanceState != null && savedInstanceState.containsKey(KEY_PROJECT_PATH)) { @@ -260,6 +272,14 @@ abstract class BaseEditorActivity : super.onSaveInstanceState(outState) } + override fun invalidateOptionsMenu() { + val mainHandler = ThreadUtils.getMainHandler() + optionsMenuInvalidator?.also { + mainHandler.removeCallbacks(it) + mainHandler.postDelayed(it, OPTIONS_MENU_INVALIDATION_DELAY) + } + } + override fun onTabSelected(tab: Tab) { val position = tab.position editorViewModel.displayedFileIndex = position diff --git a/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt b/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt index 0bfee85ef..87afa2f6e 100644 --- a/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt +++ b/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt @@ -23,6 +23,7 @@ import android.os.Bundle import android.text.TextUtils import android.util.SparseArray import android.view.Menu +import android.view.MenuItem import android.view.ViewGroup.LayoutParams import androidx.appcompat.view.menu.MenuBuilder import androidx.core.util.forEach @@ -64,8 +65,6 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.io.File import java.util.concurrent.atomic.AtomicBoolean -import kotlin.collections.component1 -import kotlin.collections.component2 import kotlin.collections.set /** @@ -138,14 +137,6 @@ open class EditorHandlerActivity : ProjectHandlerActivity(), IEditorHandler { } } - @SuppressLint("RestrictedApi") - override fun onCreateOptionsMenu(menu: Menu?): Boolean { - if (menu is MenuBuilder) { - menu.setOptionalIconsVisible(true) - } - return true - } - override fun onPause() { super.onPause() @@ -210,10 +201,72 @@ open class EditorHandlerActivity : ProjectHandlerActivity(), IEditorHandler { } override fun onPrepareOptionsMenu(menu: Menu): Boolean { - ensureToolbarMenu(menu) + prepareOptionsMenu(menu) return true } + @SuppressLint("RestrictedApi") + override fun onCreateOptionsMenu(menu: Menu): Boolean { + if (menu is MenuBuilder) { + menu.setOptionalIconsVisible(true) + } + + val data = createToolbarActionData() + getInstance().fillMenu(FillMenuParams(data, EDITOR_TOOLBAR, menu)) + return true + } + + open fun prepareOptionsMenu(menu: Menu) { + val data = createToolbarActionData() + val actions = getInstance().getActions(EDITOR_TOOLBAR) + actions.forEach { (_, action) -> + menu.findItem(action.itemId)?.let { item -> + action.prepare(data) + + item.isVisible = action.visible + item.isEnabled = action.enabled + item.title = action.label + + item.icon = action.icon?.apply { + colorFilter = action.createColorFilter(data) + alpha = if (action.enabled) 255 else 76 + } + + var showAsAction = action.getShowAsActionFlags(data) + if (showAsAction == -1) { + showAsAction = if (action.icon != null) { + MenuItem.SHOW_AS_ACTION_IF_ROOM + } else { + MenuItem.SHOW_AS_ACTION_NEVER + } + } + + if (!action.enabled) { + showAsAction = MenuItem.SHOW_AS_ACTION_NEVER + } + + item.setShowAsAction(showAsAction) + + action.createActionView(data)?.let { item.actionView = it } + } + } + binding.editorToolbar.updateMenuDisplay() + } + + private fun createToolbarActionData(): ActionData { + val data = ActionData() + val currentEditor = getCurrentEditor() + + data.put(Context::class.java, this) + data.put(CodeEditorView::class.java, currentEditor) + + if (currentEditor != null) { + data.put(IDEEditor::class.java, currentEditor.editor) + data.put(File::class.java, currentEditor.file) + } + return data + } + override fun getCurrentEditor(): CodeEditorView? { return if (editorViewModel.getCurrentFileIndex() != -1) { getEditorAtIndex(editorViewModel.getCurrentFileIndex()) @@ -485,24 +538,6 @@ open class EditorHandlerActivity : ProjectHandlerActivity(), IEditorHandler { } } - open fun ensureToolbarMenu(menu: Menu) { - menu.clear() - - val data = ActionData() - val currentEditor = getCurrentEditor() - - data.put(Context::class.java, this) - data.put(CodeEditorView::class.java, currentEditor) - - if (currentEditor != null) { - data.put(IDEEditor::class.java, currentEditor.editor) - data.put(File::class.java, currentEditor.file) - } - - getInstance().fillMenu(FillMenuParams(data, EDITOR_TOOLBAR, menu)) - binding.editorToolbar.updateMenuDisplay() - } - override fun closeAll(runAfter: () -> Unit) { val count = editorViewModel.getOpenedFileCount() val unsavedFiles = diff --git a/subprojects/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveDocument.kt b/subprojects/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveDocument.kt index 53ff36aee..5f23eeb68 100644 --- a/subprojects/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveDocument.kt +++ b/subprojects/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveDocument.kt @@ -17,15 +17,10 @@ package com.itsaky.androidide.projects.models -import com.itsaky.androidide.eventbus.events.editor.ChangeType -import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent -import com.itsaky.androidide.utils.ILogger import java.io.BufferedInputStream import java.io.BufferedReader -import java.io.Closeable import java.nio.file.Path import java.time.Instant -import java.util.concurrent.Semaphore /** * A document that is opened in the editor. @@ -38,6 +33,7 @@ open class ActiveDocument( var modified: Instant, content: String = "" ) { + var content: String = content internal set