Skip to content

Commit

Permalink
Dynamically add toolbar actions using ActionsRegistry
Browse files Browse the repository at this point in the history
  • Loading branch information
itsaky committed Apr 8, 2022
1 parent 2a06e02 commit abc847c
Show file tree
Hide file tree
Showing 41 changed files with 1,760 additions and 204 deletions.
7 changes: 7 additions & 0 deletions .idea/ktfmt.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions actions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
37 changes: 37 additions & 0 deletions actions/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion rootProject.ext.compileSdk
buildToolsVersion rootProject.ext.buildTools

defaultConfig {
minSdkVersion rootProject.ext.minSdk
targetSdkVersion rootProject.ext.targetSdk
}

buildFeatures.viewBinding true

compileOptions {
sourceCompatibility rootProject.ext.javaSourceVersion
targetCompatibility rootProject.ext.javaTargetVersion
}

buildTypes {
release {
minifyEnabled true
}
}
}

dependencies {
implementation project(':common')
implementation common.editor
implementation common.utilcode

implementation "androidx.core:core-ktx:1.7.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
repositories {
mavenCentral()
}
Empty file added actions/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions actions/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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;

import android.content.Context;

import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext () {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation ().getTargetContext ();
assertEquals ("com.itsaky.androidide.actions.test", appContext.getPackageName ());
}
}
17 changes: 17 additions & 0 deletions actions/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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/>.
-->
<manifest package="com.itsaky.androidide.actions" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
* @author Akash Yadav
*/
public class ActionData {

private final Map<Class<?>, Object> instances = new HashMap<>();

public <T> void put(@NonNull Class<T> type, @Nullable T object) {
Objects.requireNonNull(type);
this.instances.put(type, object);
}

@Nullable
public <T> T get(@NonNull Class<T> type) {
Objects.requireNonNull(type);

final var object = this.instances.get(type);
if (object == null) {
return null;
}

return type.cast(object);
}

public void clear() {
this.instances.clear();
}
}
82 changes: 82 additions & 0 deletions actions/src/main/java/com/itsaky/androidide/actions/ActionItem.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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

import android.graphics.drawable.Drawable

/**
* An action that can be registered using the [ActionsRegistry]
* [com.itsaky.androidide.actions.ActionsRegistry]
* @author Akash Yadav
*/
interface ActionItem {

val id: String
var label: String
var visible: Boolean
var enabled: Boolean
var icon: Drawable?
var requiresUIThread: Boolean
var location: Location

/**
* Prepare the action. Subclasses can modify the visual properties of this action here.
* @param data The data containing various information about the event.
*/
fun prepare(data: ActionData)

/**
* Execute the action. The action executed in a background thread by default.
*
* @param data The data containing various information about the event.
* @return `true` if this action was executed successfully, `false` otherwise.
*/
fun execAction(data: ActionData): Boolean

/**
* Called just after the [execAction] method executes **successfully** (i.e. returns `true`).
* Subclasses are free to do UI related work here as this method is called on UI thread.
*
* @param data The data containing various information about the event.
*/
fun postExec(data: ActionData, execResult: Boolean) {}

/** Location where an action item will be shown. */
enum class Location(val id: String) {

/** Location marker for action items shown in editor activity's toolbar. */
EDITOR_TOOLBAR("editor_toolbar"),

/** Location marker for action items shown in editor's text action menu. */
EDITOR_TEXT_ACTIONS("editor_text_actions"),

/**
* Location marker for action items shown in 'Code actions' submenu in editor's text action
* menu.
*/
EDITOR_CODE_ACTIONS("editor_code_actions");

override fun toString(): String {
return id
}

fun forId(id: String): Location {
return values().first { it.id == id }
}
}
}
36 changes: 36 additions & 0 deletions actions/src/main/java/com/itsaky/androidide/actions/ActionMenu.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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

/**
* An action menu is an action which can contain child actions.
* @author Akash Yadav
*/
interface ActionMenu : ActionItem {

val children: MutableSet<ActionItem>

fun addAction(action: ActionItem) = children.add(action)

fun removeAction(action: ActionItem) = children.remove(action)

/** Action menus are not supposed to perform any action */
override fun execAction(data: ActionData): Boolean {
return false
}
}
Loading

0 comments on commit abc847c

Please sign in to comment.