mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix: merge 'Quick run' and 'Cancel build' action into one
This also adds color to those actions and closes #1264
This commit is contained in:
@@ -17,9 +17,13 @@
|
||||
|
||||
package com.itsaky.androidide.actions
|
||||
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import com.itsaky.androidide.utils.resolveAttr
|
||||
|
||||
/**
|
||||
* An action that can be registered using the [ActionsRegistry]
|
||||
@@ -121,6 +125,17 @@ interface ActionItem {
|
||||
*/
|
||||
fun createActionView(data: ActionData): View? = null
|
||||
|
||||
/**
|
||||
* Creates the color filter for this action's icon drawable.
|
||||
*
|
||||
* The default implementation returns a [PorterDuffColorFilter] instance with color [R.attr.colorOnSurface].
|
||||
*/
|
||||
fun createColorFilter(data: ActionData): ColorFilter? {
|
||||
return data.getContext()?.let {
|
||||
PorterDuffColorFilter(it.resolveAttr(R.attr.colorOnSurface), PorterDuff.Mode.SRC_ATOP)
|
||||
}
|
||||
}
|
||||
|
||||
/** Location where an action item will be shown. */
|
||||
enum class Location(val id: String) {
|
||||
|
||||
|
||||
@@ -24,8 +24,12 @@ import io.github.rosemoe.sora.widget.CodeEditor
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
|
||||
fun ActionData.requireContext() : Context {
|
||||
return get(Context::class.java) ?: throw IllegalArgumentException("No context instance provided")
|
||||
fun ActionData.getContext(): Context? {
|
||||
return get(Context::class.java)
|
||||
}
|
||||
|
||||
fun ActionData.requireContext(): Context {
|
||||
return getContext() ?: throw IllegalArgumentException("No context instance provided")
|
||||
}
|
||||
|
||||
fun ActionData.requireFile(): File {
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ class DefaultActionsRegistry : ActionsRegistry() {
|
||||
item.isEnabled = action.enabled
|
||||
|
||||
item.icon = action.icon?.apply {
|
||||
colorFilter = PorterDuffColorFilter(context!!.resolveAttr(R.attr.colorOnSurface), SRC_ATOP)
|
||||
colorFilter = action.createColorFilter(data)
|
||||
}
|
||||
|
||||
if (item.icon != null) {
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.actions.build
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.itsaky.androidide.resources.R
|
||||
import com.itsaky.androidide.actions.ActionData
|
||||
import com.itsaky.androidide.actions.EditorActivityAction
|
||||
import com.itsaky.androidide.actions.markInvisible
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.projects.builder.BuildService
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
import com.itsaky.androidide.utils.flashError
|
||||
|
||||
/** @author Akash Yadav */
|
||||
class CancelBuildAction(context: Context) : EditorActivityAction() {
|
||||
|
||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||
|
||||
init {
|
||||
label = context.getString(R.string.title_cancel_build)
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_stop_daemons)
|
||||
}
|
||||
|
||||
override val id: String = "editor_stopGradleDaemons"
|
||||
|
||||
override fun prepare(data: ActionData) {
|
||||
super.prepare(data)
|
||||
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
val context = data.getActivity()
|
||||
val buildService = Lookup.getDefault().lookup(BuildService.KEY_BUILD_SERVICE)
|
||||
if (context == null || buildService == null) {
|
||||
markInvisible()
|
||||
return
|
||||
}
|
||||
|
||||
visible = true
|
||||
enabled = buildService.isBuildInProgress
|
||||
}
|
||||
|
||||
override fun execAction(data: ActionData): Boolean {
|
||||
log.info("Sending build cancellation request...")
|
||||
val builder = Lookup.getDefault().lookup(BuildService.KEY_BUILD_SERVICE)
|
||||
if (builder?.isToolingServerStarted() != true) {
|
||||
flashError(com.itsaky.androidide.projects.R.string.msg_tooling_server_unavailable)
|
||||
return false
|
||||
}
|
||||
|
||||
builder.cancelCurrentBuild().whenComplete {
|
||||
result,
|
||||
error ->
|
||||
if (error != null) {
|
||||
log.error("Failed to send build cancellation request", error)
|
||||
return@whenComplete
|
||||
}
|
||||
|
||||
if (!result.wasEnqueued) {
|
||||
log.warn(
|
||||
"Unable to enqueue cancellation request",
|
||||
result.failureReason,
|
||||
result.failureReason!!.message
|
||||
)
|
||||
return@whenComplete
|
||||
}
|
||||
|
||||
log.info("Build cancellation request was successfully enqueued...")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
+87
-2
@@ -18,13 +18,20 @@
|
||||
package com.itsaky.androidide.actions.build
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.itsaky.androidide.actions.ActionData
|
||||
import com.itsaky.androidide.actions.BaseBuildAction
|
||||
import com.itsaky.androidide.actions.getContext
|
||||
import com.itsaky.androidide.actions.markInvisible
|
||||
import com.itsaky.androidide.actions.requireContext
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.models.ApkMetadata
|
||||
import com.itsaky.androidide.projects.IProjectManager
|
||||
import com.itsaky.androidide.projects.api.AndroidModule
|
||||
import com.itsaky.androidide.projects.builder.BuildService
|
||||
import com.itsaky.androidide.resources.R
|
||||
import com.itsaky.androidide.tasks.executeAsyncProvideError
|
||||
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult
|
||||
@@ -33,18 +40,23 @@ import com.itsaky.androidide.utils.ApkInstaller
|
||||
import com.itsaky.androidide.utils.DialogUtils
|
||||
import com.itsaky.androidide.utils.InstallationResultHandler
|
||||
import com.itsaky.androidide.utils.flashError
|
||||
import com.itsaky.androidide.utils.resolveAttr
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* The 'Quick Run' action in the editor activity.
|
||||
* The 'Quick Run' and 'Cancel build' action in the editor activity.
|
||||
*
|
||||
* If a build is in progress, executing this action cancels the build. Otherwise, the selected
|
||||
* build variant is built and installed to the device.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class QuickRunAction(context: Context) : BaseBuildAction() {
|
||||
class QuickRunWithCancellationAction(context: Context) : BaseBuildAction() {
|
||||
|
||||
init {
|
||||
label = context.getString(R.string.quick_run_debug)
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_outline)
|
||||
enabled = false
|
||||
}
|
||||
|
||||
override val id: String = "ide.editor.build.quickRun"
|
||||
@@ -52,7 +64,44 @@ class QuickRunAction(context: Context) : BaseBuildAction() {
|
||||
// Execute on UI thread as this action might try to show dialogs to the user
|
||||
override var requiresUIThread: Boolean = true
|
||||
|
||||
override fun prepare(data: ActionData) {
|
||||
|
||||
val context = data.getActivity() ?: run {
|
||||
markInvisible()
|
||||
return
|
||||
}
|
||||
|
||||
if (data.isBuildInProgress()) {
|
||||
label = context.getString(R.string.title_cancel_build)
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_stop_daemons)
|
||||
|
||||
visible = true
|
||||
enabled = true
|
||||
} else {
|
||||
label = context.getString(R.string.quick_run_debug)
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_outline)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createColorFilter(data: ActionData): ColorFilter? {
|
||||
return data.getContext()?.let {
|
||||
PorterDuffColorFilter(it.resolveAttr(
|
||||
if (data.isBuildInProgress())
|
||||
R.attr.colorError
|
||||
else R.attr.colorSuccess
|
||||
), PorterDuff.Mode.SRC_ATOP)
|
||||
}
|
||||
}
|
||||
|
||||
override fun execAction(data: ActionData): Boolean {
|
||||
if (data.isBuildInProgress()) {
|
||||
return cancelBuild()
|
||||
}
|
||||
|
||||
return quickRun(data)
|
||||
}
|
||||
|
||||
private fun quickRun(data: ActionData): Boolean {
|
||||
chooseApplication(data) { module ->
|
||||
val activity = data.requireActivity()
|
||||
|
||||
@@ -81,6 +130,36 @@ class QuickRunAction(context: Context) : BaseBuildAction() {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun cancelBuild(): Boolean {
|
||||
log.info("Sending build cancellation request...")
|
||||
val builder = Lookup.getDefault().lookup(BuildService.KEY_BUILD_SERVICE)
|
||||
if (builder?.isToolingServerStarted() != true) {
|
||||
flashError(com.itsaky.androidide.projects.R.string.msg_tooling_server_unavailable)
|
||||
return false
|
||||
}
|
||||
|
||||
builder.cancelCurrentBuild().whenComplete { result,
|
||||
error ->
|
||||
if (error != null) {
|
||||
log.error("Failed to send build cancellation request", error)
|
||||
return@whenComplete
|
||||
}
|
||||
|
||||
if (!result.wasEnqueued) {
|
||||
log.warn(
|
||||
"Unable to enqueue cancellation request",
|
||||
result.failureReason,
|
||||
result.failureReason!!.message
|
||||
)
|
||||
return@whenComplete
|
||||
}
|
||||
|
||||
log.info("Build cancellation request was successfully enqueued...")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun handleResult(
|
||||
data: ActionData,
|
||||
result: TaskExecutionResult?,
|
||||
@@ -170,4 +249,10 @@ class QuickRunAction(context: Context) : BaseBuildAction() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ActionData.isBuildInProgress(): Boolean {
|
||||
val context = getActivity()
|
||||
val buildService = Lookup.getDefault().lookup(BuildService.KEY_BUILD_SERVICE)
|
||||
return context?.editorViewModel?.let { it.isInitializing || it.isBuildInProgress } == true || buildService?.isBuildInProgress == true
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,8 @@ import com.itsaky.androidide.actions.ActionItem.Location.EDITOR_FILE_TABS
|
||||
import com.itsaky.androidide.actions.ActionItem.Location.EDITOR_FILE_TREE
|
||||
import com.itsaky.androidide.actions.ActionItem.Location.EDITOR_TOOLBAR
|
||||
import com.itsaky.androidide.actions.ActionsRegistry
|
||||
import com.itsaky.androidide.actions.build.CancelBuildAction
|
||||
import com.itsaky.androidide.actions.build.ProjectSyncAction
|
||||
import com.itsaky.androidide.actions.build.QuickRunAction
|
||||
import com.itsaky.androidide.actions.build.QuickRunWithCancellationAction
|
||||
import com.itsaky.androidide.actions.build.RunTasksAction
|
||||
import com.itsaky.androidide.actions.editor.CopyAction
|
||||
import com.itsaky.androidide.actions.editor.CutAction
|
||||
@@ -66,13 +65,12 @@ class EditorActivityActions {
|
||||
// Toolbar actions
|
||||
registry.registerAction(UndoAction(context))
|
||||
registry.registerAction(RedoAction(context))
|
||||
registry.registerAction(QuickRunAction(context))
|
||||
registry.registerAction(QuickRunWithCancellationAction(context))
|
||||
registry.registerAction(RunTasksAction(context))
|
||||
registry.registerAction(SaveFileAction(context))
|
||||
registry.registerAction(PreviewLayoutAction(context))
|
||||
registry.registerAction(FindActionMenu(context))
|
||||
registry.registerAction(FileTreeAction(context))
|
||||
registry.registerAction(CancelBuildAction(context))
|
||||
registry.registerAction(ProjectSyncAction(context))
|
||||
registry.registerAction(ReloadColorSchemesAction(context))
|
||||
registry.registerAction(DisconnectLogSendersAction(context))
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
android:layout_marginEnd="16dp"
|
||||
android:tooltipText="@string/run"
|
||||
app:icon="@drawable/ic_run"
|
||||
app:iconTint="@color/green_500" />
|
||||
app:iconTint="?attr/colorSuccess" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -18,8 +18,11 @@
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- Color used for success drawables-->
|
||||
<attr format="color" name="colorSuccess" />
|
||||
|
||||
<declare-styleable name="VectorMasterView">
|
||||
<attr name="vector_src" format="reference" />
|
||||
<attr name="use_legacy_parser" format="boolean" />
|
||||
<attr format="reference" name="vector_src" />
|
||||
<attr format="boolean" name="use_legacy_parser" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
<item name="switchPreferenceStyle">@style/AppTheme.SwitchPreference</item>
|
||||
<item name="shapeAppearanceLargeComponent">@style/AppTheme.ShapeOverlay.Large</item>
|
||||
<item name="textAppearanceBodySmall">@style/TextAppearance.AndroidIDE.BodySmall</item>
|
||||
<item name="colorSuccess">@color/green_500</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AndroidIDE" parent="Theme.AndroidIDE.Styled">
|
||||
|
||||
Reference in New Issue
Block a user