feat: 插件菜单入口
This commit is contained in:
parent
c306846e7e
commit
c2af149d1d
|
|
@ -1,9 +1,11 @@
|
||||||
[
|
{
|
||||||
{
|
"plugins": [
|
||||||
"id": "CommentLookup",
|
{
|
||||||
"name": "发言查询",
|
"id": "CommentLookup",
|
||||||
"desc": "使用第三方工具箱查询用户过往发言",
|
"name": "发言查询",
|
||||||
"version": "1.0",
|
"desc": "使用第三方工具箱查询用户过往发言",
|
||||||
"mainClass": "com.huanchengfly.tieba.post.plugins.PluginCommentLookup"
|
"version": "1.0",
|
||||||
}
|
"main_class": "com.huanchengfly.tieba.post.plugins.PluginCommentLookup"
|
||||||
]
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,6 @@ import android.graphics.Color
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
|
@ -41,26 +40,25 @@ class BaseApplication : Application(), IApp {
|
||||||
instance = this
|
instance = this
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
ThemeUtils.init(ThemeDelegate)
|
ThemeUtils.init(ThemeDelegate)
|
||||||
PluginManager.init(this)
|
|
||||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||||
LitePal.initialize(this)
|
LitePal.initialize(this)
|
||||||
FlurryAgent.Builder()
|
FlurryAgent.Builder()
|
||||||
.withCaptureUncaughtExceptions(true)
|
.withCaptureUncaughtExceptions(true)
|
||||||
.build(this, "ZMRX6W76WNF95ZHT857X")
|
.build(this, "ZMRX6W76WNF95ZHT857X")
|
||||||
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
|
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
|
||||||
private var clipBoardHash: String? = null
|
private var clipBoardHash: Int = 0
|
||||||
private fun updateClipBoardHashCode() {
|
private fun updateClipBoardHashCode() {
|
||||||
clipBoardHash = getClipBoardHash()
|
clipBoardHash = getClipBoardHash()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getClipBoardHash(): String? {
|
private fun getClipBoardHash(): Int {
|
||||||
val cm = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val cm = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
val data = cm.primaryClip
|
val data = cm.primaryClip
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
val item = data.getItemAt(0)
|
val item = data.getItemAt(0)
|
||||||
return item.toString().toMD5()
|
return item.hashCode()
|
||||||
}
|
}
|
||||||
return null
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private val clipBoard: String
|
private val clipBoard: String
|
||||||
|
|
@ -117,8 +115,9 @@ class BaseApplication : Application(), IApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResumed(activity: Activity) {
|
override fun onActivityResumed(activity: Activity) {
|
||||||
if (!TextUtils.equals(clipBoardHash, getClipBoardHash())) {
|
if (clipBoardHash != getClipBoardHash()) {
|
||||||
@RegExp val regex = "((http|https)://)(([a-zA-Z0-9._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9&%_./-~-]*)?"
|
@RegExp val regex =
|
||||||
|
"((http|https)://)(([a-zA-Z0-9._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9&%_./-~-]*)?"
|
||||||
val pattern = Pattern.compile(regex)
|
val pattern = Pattern.compile(regex)
|
||||||
val matcher = pattern.matcher(clipBoard)
|
val matcher = pattern.matcher(clipBoard)
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
|
|
@ -127,7 +126,8 @@ class BaseApplication : Application(), IApp {
|
||||||
if (isTiebaDomain(uri.host)) {
|
if (isTiebaDomain(uri.host)) {
|
||||||
val previewView = Util.inflate(activity, R.layout.preview_url)
|
val previewView = Util.inflate(activity, R.layout.preview_url)
|
||||||
if (isForumUrl(uri)) {
|
if (isForumUrl(uri)) {
|
||||||
updatePreviewView(activity, previewView, PreviewInfo()
|
updatePreviewView(
|
||||||
|
activity, previewView, PreviewInfo()
|
||||||
.setIconRes(R.drawable.ic_round_forum)
|
.setIconRes(R.drawable.ic_round_forum)
|
||||||
.setTitle(activity.getString(R.string.title_forum, getForumName(uri)))
|
.setTitle(activity.getString(R.string.title_forum, getForumName(uri)))
|
||||||
.setSubtitle(activity.getString(R.string.text_loading))
|
.setSubtitle(activity.getString(R.string.text_loading))
|
||||||
|
|
@ -174,6 +174,7 @@ class BaseApplication : Application(), IApp {
|
||||||
override fun onActivityDestroyed(activity: Activity) {}
|
override fun onActivityDestroyed(activity: Activity) {}
|
||||||
})
|
})
|
||||||
CrashUtil.CrashHandler.getInstance().init(this)
|
CrashUtil.CrashHandler.getInstance().init(this)
|
||||||
|
PluginManager.init(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import com.huanchengfly.tieba.post.fragments.UserPostFragment
|
||||||
import com.huanchengfly.tieba.post.goToActivity
|
import com.huanchengfly.tieba.post.goToActivity
|
||||||
import com.huanchengfly.tieba.post.models.PhotoViewBean
|
import com.huanchengfly.tieba.post.models.PhotoViewBean
|
||||||
import com.huanchengfly.tieba.post.models.database.Block
|
import com.huanchengfly.tieba.post.models.database.Block
|
||||||
|
import com.huanchengfly.tieba.post.plugins.PluginManager
|
||||||
import com.huanchengfly.tieba.post.utils.AccountUtil
|
import com.huanchengfly.tieba.post.utils.AccountUtil
|
||||||
import com.huanchengfly.tieba.post.utils.ImageUtil
|
import com.huanchengfly.tieba.post.utils.ImageUtil
|
||||||
import com.huanchengfly.tieba.post.utils.StatusBarUtil
|
import com.huanchengfly.tieba.post.utils.StatusBarUtil
|
||||||
|
|
@ -187,6 +188,7 @@ class UserActivity : BaseActivity() {
|
||||||
menu.findItem(R.id.menu_block).isVisible = true
|
menu.findItem(R.id.menu_block).isVisible = true
|
||||||
menu.findItem(R.id.menu_edit_info).isVisible = false
|
menu.findItem(R.id.menu_edit_info).isVisible = false
|
||||||
}
|
}
|
||||||
|
PluginManager.initPluginMenu(menu, PluginManager.MENU_USER_ACTIVITY)
|
||||||
return super.onCreateOptionsMenu(menu)
|
return super.onCreateOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,7 +207,8 @@ class UserActivity : BaseActivity() {
|
||||||
.saveAsync()
|
.saveAsync()
|
||||||
.listen { success: Boolean ->
|
.listen { success: Boolean ->
|
||||||
if (success) {
|
if (success) {
|
||||||
Toast.makeText(this, R.string.toast_add_success, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.toast_add_success, Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -215,7 +218,17 @@ class UserActivity : BaseActivity() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item)
|
return if (PluginManager.performPluginMenuClick(
|
||||||
|
this,
|
||||||
|
PluginManager.MENU_USER_ACTIVITY,
|
||||||
|
item.itemId,
|
||||||
|
profileBean
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.user_center_action_btn)
|
@OnClick(R.id.user_center_action_btn)
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,11 @@ inline fun <reified Data> IPlugin.registerMenuItem(
|
||||||
inline fun <reified Data> IPlugin.registerMenuItem(
|
inline fun <reified Data> IPlugin.registerMenuItem(
|
||||||
id: String,
|
id: String,
|
||||||
title: String,
|
title: String,
|
||||||
crossinline callback: (Data) -> Unit
|
crossinline callback: (Context, Data) -> Unit
|
||||||
) {
|
) {
|
||||||
registerMenuItem(id, title, object : ClickCallback<Data> {
|
registerMenuItem(id, title, object : ClickCallback<Data> {
|
||||||
override fun onClick(data: Data) {
|
override fun onClick(context: Context, data: Data) {
|
||||||
callback.invoke(data)
|
callback.invoke(context, data)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.huanchengfly.tieba.post.R
|
||||||
import com.huanchengfly.tieba.post.api.models.ProfileBean
|
import com.huanchengfly.tieba.post.api.models.ProfileBean
|
||||||
import com.huanchengfly.tieba.post.plugins.interfaces.IApp
|
import com.huanchengfly.tieba.post.plugins.interfaces.IApp
|
||||||
import com.huanchengfly.tieba.post.plugins.models.PluginManifest
|
import com.huanchengfly.tieba.post.plugins.models.PluginManifest
|
||||||
|
import com.huanchengfly.tieba.post.utils.launchUrl
|
||||||
|
|
||||||
class PluginCommentLookup(app: IApp, manifest: PluginManifest) : IPlugin(app, manifest) {
|
class PluginCommentLookup(app: IApp, manifest: PluginManifest) : IPlugin(app, manifest) {
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
|
|
@ -11,8 +12,8 @@ class PluginCommentLookup(app: IApp, manifest: PluginManifest) : IPlugin(app, ma
|
||||||
registerMenuItem<ProfileBean>(
|
registerMenuItem<ProfileBean>(
|
||||||
"lookup_comment",
|
"lookup_comment",
|
||||||
context.getString(R.string.plugin_comment_lookup_menu)
|
context.getString(R.string.plugin_comment_lookup_menu)
|
||||||
) {
|
) { context, data ->
|
||||||
app.launchUrl("https://www.82cat.com/tieba/reply/${it.user?.name}/1")
|
launchUrl(context, "https://www.82cat.com/tieba/reply/${data.user?.name}/1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,9 +2,11 @@ package com.huanchengfly.tieba.post.plugins
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.view.Menu
|
||||||
import com.huanchengfly.tieba.post.api.models.ProfileBean
|
import com.huanchengfly.tieba.post.api.models.ProfileBean
|
||||||
import com.huanchengfly.tieba.post.fromJson
|
import com.huanchengfly.tieba.post.fromJson
|
||||||
import com.huanchengfly.tieba.post.plugins.interfaces.IApp
|
import com.huanchengfly.tieba.post.plugins.interfaces.IApp
|
||||||
|
import com.huanchengfly.tieba.post.plugins.models.BuiltInPlugins
|
||||||
import com.huanchengfly.tieba.post.plugins.models.PluginManifest
|
import com.huanchengfly.tieba.post.plugins.models.PluginManifest
|
||||||
import com.huanchengfly.tieba.post.utils.AssetUtil
|
import com.huanchengfly.tieba.post.utils.AssetUtil
|
||||||
import com.huanchengfly.tieba.post.utils.SharedPreferencesUtil
|
import com.huanchengfly.tieba.post.utils.SharedPreferencesUtil
|
||||||
|
|
@ -19,7 +21,7 @@ object PluginManager {
|
||||||
val pluginManifests: MutableList<PluginManifest> = mutableListOf()
|
val pluginManifests: MutableList<PluginManifest> = mutableListOf()
|
||||||
val pluginInstances: MutableList<IPlugin> = mutableListOf()
|
val pluginInstances: MutableList<IPlugin> = mutableListOf()
|
||||||
|
|
||||||
val registeredPluginMenuItems: MutableMap<String, MutableMap<String, PluginMenuItem<*>>> =
|
val registeredPluginMenuItems: MutableMap<String, MutableMap<Int, PluginMenuItem<*>>> =
|
||||||
mutableMapOf()
|
mutableMapOf()
|
||||||
|
|
||||||
val context: Context
|
val context: Context
|
||||||
|
|
@ -37,7 +39,7 @@ object PluginManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Data> registerMenuItem(pluginInstance: IPlugin, menuItem: PluginMenuItem<Data>) {
|
fun <Data> registerMenuItem(pluginInstance: IPlugin, menuItem: PluginMenuItem<Data>) {
|
||||||
registeredPluginMenuItems[menuItem.menuId]!!["${pluginInstance.manifest.id}_${menuItem.id}"] =
|
registeredPluginMenuItems[menuItem.menuId]!!["${pluginInstance.manifest.id}_${menuItem.id}".hashCode()] =
|
||||||
menuItem
|
menuItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,6 +48,32 @@ object PluginManager {
|
||||||
reloadPlugins()
|
reloadPlugins()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun initPluginMenu(menu: Menu, menuId: String) {
|
||||||
|
val menuItems = registeredPluginMenuItems[menuId]!!
|
||||||
|
menuItems.forEach {
|
||||||
|
menu.add(0, it.key, 0, it.value.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Data> performPluginMenuClick(
|
||||||
|
context: Context,
|
||||||
|
menuId: String,
|
||||||
|
itemId: Int,
|
||||||
|
data: Data
|
||||||
|
): Boolean {
|
||||||
|
val menuItems = registeredPluginMenuItems[menuId]!!
|
||||||
|
val item = menuItems[itemId]
|
||||||
|
if (item?.callback == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
(item as PluginMenuItem<Data>).callback!!.onClick(context, data)
|
||||||
|
true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun enablePlugin(id: String) {
|
fun enablePlugin(id: String) {
|
||||||
pluginInstances.filter { it.manifest.id == id }.forEach { enablePlugin(it) }
|
pluginInstances.filter { it.manifest.id == id }.forEach { enablePlugin(it) }
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +122,7 @@ object PluginManager {
|
||||||
fun reloadPluginManifests() {
|
fun reloadPluginManifests() {
|
||||||
pluginManifests.clear()
|
pluginManifests.clear()
|
||||||
pluginManifests.addAll(
|
pluginManifests.addAll(
|
||||||
AssetUtil.getStringFromAsset(context, "plugins.json").fromJson<List<PluginManifest>>()
|
AssetUtil.getStringFromAsset(context, "plugins.json").fromJson<BuiltInPlugins>().plugins
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +135,7 @@ object PluginManager {
|
||||||
reloadPluginManifests()
|
reloadPluginManifests()
|
||||||
pluginManifests.forEach {
|
pluginManifests.forEach {
|
||||||
try {
|
try {
|
||||||
if (it.pluginCreated && preferences.getBoolean("${it.id}_enabled", true)) {
|
if (!it.pluginCreated && preferences.getBoolean("${it.id}_enabled", true)) {
|
||||||
val pluginInstance = createPlugin(it)
|
val pluginInstance = createPlugin(it)
|
||||||
if (pluginInstance != null) {
|
if (pluginInstance != null) {
|
||||||
pluginInstances.add(pluginInstance)
|
pluginInstances.add(pluginInstance)
|
||||||
|
|
@ -135,7 +163,7 @@ class PluginMenuItem<Data>(
|
||||||
val callback: ClickCallback<Data>? = null
|
val callback: ClickCallback<Data>? = null
|
||||||
) {
|
) {
|
||||||
interface ClickCallback<Data> {
|
interface ClickCallback<Data> {
|
||||||
fun onClick(data: Data)
|
fun onClick(context: Context, data: Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.huanchengfly.tieba.post.plugins.models
|
||||||
|
|
||||||
|
data class BuiltInPlugins(
|
||||||
|
val plugins: List<PluginManifest>
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue