Skip to content

Commit 60b767e

Browse files
committed
ADFA-3598: Move jetpack preview into a plugin
1 parent fd2ee2d commit 60b767e

36 files changed

Lines changed: 346 additions & 4595 deletions

‎actions/src/main/java/com/itsaky/androidide/actions/ActionItem.kt‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ interface ActionItem {
113113
val itemId: Int
114114
get() = id.hashCode()
115115

116+
/**
117+
* Whether the editor toolbar should fully remove this action when [visible] is false,
118+
* instead of the legacy behaviour of keeping it and only greying out when disabled.
119+
* Built-in actions keep the legacy behaviour (default false); plugin-contributed
120+
* toolbar actions opt in by overriding this to true.
121+
*/
122+
val honorVisibility: Boolean
123+
get() = false
124+
116125
/**
117126
* Prepare the action. Subclasses can modify the visual properties of this action here.
118127
*

‎app/build.gradle.kts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,6 @@ dependencies {
323323

324324
implementation(projects.layouteditor)
325325
implementation(projects.idetooltips)
326-
implementation(projects.composePreview)
327326
implementation(projects.gitCore)
328327

329328
// This is to build the tooling-api-impl project before the app is built
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.itsaky.androidide.actions
2+
3+
import android.content.Context
4+
import android.util.Log
5+
import android.view.MenuItem
6+
import androidx.core.content.ContextCompat
7+
import com.itsaky.androidide.R
8+
import com.itsaky.androidide.plugins.extensions.ShowAsAction
9+
import com.itsaky.androidide.plugins.extensions.ToolbarAction
10+
import com.itsaky.androidide.plugins.manager.pluginCategory
11+
import com.itsaky.androidide.plugins.manager.pluginTooltipTag
12+
import com.itsaky.androidide.plugins.manager.ui.PluginDrawableResolver
13+
14+
/**
15+
* Adapts a plugin-contributed [ToolbarAction] (from `UIExtension.getToolbarActions()`)
16+
* into an editor-toolbar [ActionItem].
17+
*
18+
* Unlike [PluginActionItem] (which wraps `getMainMenuItems()`), this is the dedicated
19+
* path for toolbar icons: it carries the action's own [ToolbarAction.order] so a plugin
20+
* can position its icon among the built-in actions, and it opts into [honorVisibility]
21+
* so the toolbar fully removes it (instead of greying it) when not applicable.
22+
*/
23+
class PluginToolbarActionItem(
24+
context: Context,
25+
private val toolbarAction: ToolbarAction,
26+
val pluginId: String
27+
) : EditorActivityAction() {
28+
29+
override val id: String = "plugin.toolbar.${toolbarAction.id}"
30+
31+
override val order: Int = toolbarAction.order
32+
33+
override val honorVisibility: Boolean get() = true
34+
35+
init {
36+
label = toolbarAction.title
37+
val iconResId = toolbarAction.icon
38+
icon = if (iconResId != null) {
39+
PluginDrawableResolver.resolve(iconResId, pluginId, context)
40+
?: ContextCompat.getDrawable(context, R.drawable.ic_package)
41+
} else {
42+
ContextCompat.getDrawable(context, R.drawable.ic_package)
43+
}
44+
location = ActionItem.Location.EDITOR_TOOLBAR
45+
requiresUIThread = true
46+
}
47+
48+
override fun prepare(data: ActionData) {
49+
super.prepare(data)
50+
if (!visible) {
51+
// EditorActivityAction.prepare() hides the action when the editor context is
52+
// missing; respect that and skip the plugin providers.
53+
return
54+
}
55+
runCatching {
56+
enabled = toolbarAction.isEnabledProvider?.invoke() ?: toolbarAction.isEnabled
57+
visible = toolbarAction.isVisibleProvider?.invoke() ?: toolbarAction.isVisible
58+
}.onFailure { e ->
59+
// A throwing/disposed plugin must never keep a stale icon on the toolbar.
60+
Log.w("PluginToolbarActionItem", "prepare failed for '${toolbarAction.id}'", e)
61+
enabled = false
62+
visible = false
63+
}
64+
}
65+
66+
override fun getShowAsActionFlags(data: ActionData): Int = when (toolbarAction.showAsAction) {
67+
ShowAsAction.ALWAYS -> MenuItem.SHOW_AS_ACTION_ALWAYS
68+
ShowAsAction.IF_ROOM -> MenuItem.SHOW_AS_ACTION_IF_ROOM
69+
ShowAsAction.NEVER -> MenuItem.SHOW_AS_ACTION_NEVER
70+
ShowAsAction.WITH_TEXT -> MenuItem.SHOW_AS_ACTION_WITH_TEXT
71+
ShowAsAction.COLLAPSE_ACTION_VIEW -> MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
72+
}
73+
74+
override fun retrieveTooltipTag(isReadOnlyContext: Boolean): String =
75+
pluginTooltipTag(pluginId, toolbarAction.id)
76+
77+
override fun retrieveTooltipCategory(): String = pluginCategory(pluginId)
78+
79+
override suspend fun execAction(data: ActionData): Any {
80+
return try {
81+
toolbarAction.action.invoke()
82+
true
83+
} catch (e: Exception) {
84+
Log.e("PluginToolbarActionItem", "Error executing toolbar action '${toolbarAction.id}'", e)
85+
false
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)