feat: 枝网查重(插件)
This commit is contained in:
parent
ec65fbdb08
commit
9a26537f12
|
|
@ -7,6 +7,14 @@
|
|||
"author": "huanchengfly",
|
||||
"version": "1.0",
|
||||
"main_class": "com.huanchengfly.tieba.post.plugins.PluginCommentLookup"
|
||||
},
|
||||
{
|
||||
"id": "AsoulCnki",
|
||||
"name": "枝网查重",
|
||||
"desc": "调用枝网查重 API 查询重复小作文",
|
||||
"author": "huanchengfly",
|
||||
"version": "1.0",
|
||||
"main_class": "com.huanchengfly.tieba.post.plugins.asoulcnki.PluginAsoulCnki"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -77,8 +77,8 @@ class BaseApplication : Application(), IApp {
|
|||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
LitePal.initialize(this)
|
||||
FlurryAgent.Builder()
|
||||
.withCaptureUncaughtExceptions(true)
|
||||
.build(this, "ZMRX6W76WNF95ZHT857X")
|
||||
.withCaptureUncaughtExceptions(true)
|
||||
.build(this, "ZMRX6W76WNF95ZHT857X")
|
||||
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
|
||||
private var clipBoardHash: Int = 0
|
||||
private fun updateClipBoardHashCode() {
|
||||
|
|
@ -517,7 +517,33 @@ class BaseApplication : Application(), IApp {
|
|||
return this
|
||||
}
|
||||
|
||||
override fun getCurrentContext(): Context {
|
||||
return mActivityList.lastOrNull() ?: this
|
||||
}
|
||||
|
||||
override fun launchUrl(url: String) {
|
||||
launchUrl(mActivityList.lastOrNull() ?: this, url)
|
||||
launchUrl(getCurrentContext(), url)
|
||||
}
|
||||
|
||||
override fun showLoadingDialog(): Dialog {
|
||||
return LoadingDialog(getCurrentContext()).apply { show() }
|
||||
}
|
||||
|
||||
override fun toastShort(text: String) {
|
||||
getCurrentContext().toastShort(text)
|
||||
}
|
||||
|
||||
override fun showAlertDialog(builder: AlertDialog.Builder.() -> Unit): AlertDialog {
|
||||
val dialog = AlertDialog.Builder(getCurrentContext())
|
||||
.apply(builder)
|
||||
.create()
|
||||
if (getCurrentContext() !is BaseActivity || (getCurrentContext() as BaseActivity).isActivityRunning) {
|
||||
dialog.show()
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
override fun copyText(text: String) {
|
||||
TiebaUtil.copyText(getCurrentContext(), text)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,16 +5,19 @@ import android.app.Activity
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.huanchengfly.tieba.post.utils.GsonUtil
|
||||
import com.huanchengfly.tieba.post.utils.MD5Util
|
||||
|
||||
|
||||
fun Float.dpToPx(): Int =
|
||||
dpToPxFloat().toInt()
|
||||
|
||||
|
|
@ -38,26 +41,21 @@ fun Int.pxToDp(): Int = this.toFloat().pxToDp()
|
|||
|
||||
fun Int.pxToSp(): Int = this.toFloat().pxToSp()
|
||||
|
||||
inline fun <reified Data> String.fromJson() = GsonUtil.getGson().fromJson<Data>(this, Data::class.java)
|
||||
inline fun <reified Data> String.fromJson(): Data {
|
||||
val type = object : TypeToken<Data>() {}.type
|
||||
return GsonUtil.getGson().fromJson(this, type)
|
||||
}
|
||||
|
||||
fun Any.toJson(): String = Gson().toJson(this)
|
||||
|
||||
fun String.toMD5(): String = MD5Util.toMd5(this)
|
||||
|
||||
fun Context.getColorCompat(@ColorRes id: Int): Int {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
resources.getColor(id, theme)
|
||||
} else {
|
||||
resources.getColor(id)
|
||||
}
|
||||
return ContextCompat.getColor(this, id)
|
||||
}
|
||||
|
||||
fun Context.getColorStateListCompat(id: Int): ColorStateList {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
resources.getColorStateList(id, theme)
|
||||
} else {
|
||||
resources.getColorStateList(id)
|
||||
}
|
||||
return AppCompatResources.getColorStateList(this, id)
|
||||
}
|
||||
|
||||
inline fun <reified T : Activity> Context.goToActivity() {
|
||||
|
|
|
|||
|
|
@ -508,7 +508,6 @@ class ThreadActivity : BaseActivity(), View.OnClickListener, IThreadMenuFragment
|
|||
totalPage = Integer.valueOf(threadContentBean.page.totalPage!!)
|
||||
refresh(pid)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import com.huanchengfly.tieba.post.fragments.ConfirmDialogFragment;
|
|||
import com.huanchengfly.tieba.post.fragments.MenuDialogFragment;
|
||||
import com.huanchengfly.tieba.post.models.PhotoViewBean;
|
||||
import com.huanchengfly.tieba.post.models.ReplyInfoBean;
|
||||
import com.huanchengfly.tieba.post.plugins.PluginManager;
|
||||
import com.huanchengfly.tieba.post.utils.AccountUtil;
|
||||
import com.huanchengfly.tieba.post.utils.BilibiliUtil;
|
||||
import com.huanchengfly.tieba.post.utils.DateTimeUtils;
|
||||
|
|
@ -178,9 +179,10 @@ public class RecyclerFloorAdapter extends CommonBaseAdapter<SubFloorListBean.Pos
|
|||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return PluginManager.INSTANCE.performPluginMenuClick(PluginManager.MENU_SUB_POST_ITEM, item.getItemId(), postInfo);
|
||||
})
|
||||
.setInitMenuCallback(menu -> {
|
||||
PluginManager.INSTANCE.initPluginMenu(menu, PluginManager.MENU_SUB_POST_ITEM);
|
||||
if (TextUtils.equals(AccountUtil.getLoginInfo(mContext).getUid(), postInfo.getAuthor().getId())) {
|
||||
menu.findItem(R.id.menu_delete).setVisible(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.huanchengfly.tieba.post.api.models.ThreadContentBean
|
|||
import com.huanchengfly.tieba.post.components.MyViewHolder
|
||||
import com.huanchengfly.tieba.post.fragments.MenuDialogFragment
|
||||
import com.huanchengfly.tieba.post.models.ReplyInfoBean
|
||||
import com.huanchengfly.tieba.post.plugins.PluginManager
|
||||
import com.huanchengfly.tieba.post.utils.*
|
||||
import com.huanchengfly.tieba.post.utils.NavigationHelper
|
||||
import com.huanchengfly.tieba.post.utils.TiebaUtil.reportPost
|
||||
|
|
@ -120,13 +121,22 @@ class ThreadMainPostAdapter(
|
|||
stringBuilder.append(contentBean.text)
|
||||
}
|
||||
}
|
||||
Util.showCopyDialog(context as BaseActivity?, stringBuilder.toString(), threadPostBean!!.id)
|
||||
Util.showCopyDialog(
|
||||
context as BaseActivity?,
|
||||
stringBuilder.toString(),
|
||||
threadPostBean!!.id
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
else -> PluginManager.performPluginMenuClick(
|
||||
PluginManager.MENU_POST_ITEM,
|
||||
item.itemId,
|
||||
threadPostBean!!
|
||||
)
|
||||
}
|
||||
}
|
||||
.setInitMenuCallback { menu: Menu ->
|
||||
PluginManager.initPluginMenu(menu, PluginManager.MENU_POST_ITEM)
|
||||
menu.findItem(R.id.menu_delete).isVisible = false
|
||||
}
|
||||
.show((context as BaseActivity).supportFragmentManager, threadPostBean!!.id + "_Menu")
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import com.huanchengfly.tieba.post.fragments.ConfirmDialogFragment
|
|||
import com.huanchengfly.tieba.post.fragments.FloorFragment.Companion.newInstance
|
||||
import com.huanchengfly.tieba.post.fragments.MenuDialogFragment
|
||||
import com.huanchengfly.tieba.post.models.ReplyInfoBean
|
||||
import com.huanchengfly.tieba.post.plugins.PluginManager
|
||||
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils
|
||||
import com.huanchengfly.tieba.post.utils.*
|
||||
import com.huanchengfly.tieba.post.utils.BilibiliUtil.replaceVideoNumberSpan
|
||||
|
|
@ -314,9 +315,14 @@ class ThreadReplyAdapter(context: Context) : BaseSingleTypeDelegateAdapter<PostL
|
|||
return@setOnNavigationItemSelectedListener true
|
||||
}
|
||||
}
|
||||
false
|
||||
PluginManager.performPluginMenuClick(
|
||||
PluginManager.MENU_SUB_POST_ITEM,
|
||||
item.itemId,
|
||||
subPostListItemBean
|
||||
)
|
||||
}
|
||||
.setInitMenuCallback { menu: Menu ->
|
||||
PluginManager.initPluginMenu(menu, PluginManager.MENU_SUB_POST_ITEM)
|
||||
menu.findItem(R.id.menu_report).isVisible = false
|
||||
if (TextUtils.equals(AccountUtil.getUid(context), subPostListItemBean.authorId)) {
|
||||
menu.findItem(R.id.menu_delete).isVisible = true
|
||||
|
|
@ -384,9 +390,14 @@ class ThreadReplyAdapter(context: Context) : BaseSingleTypeDelegateAdapter<PostL
|
|||
return@setOnNavigationItemSelectedListener true
|
||||
}
|
||||
}
|
||||
false
|
||||
PluginManager.performPluginMenuClick(
|
||||
PluginManager.MENU_POST_ITEM,
|
||||
item.itemId,
|
||||
postListItemBean
|
||||
)
|
||||
}
|
||||
.setInitMenuCallback { menu: Menu ->
|
||||
PluginManager.initPluginMenu(menu, PluginManager.MENU_POST_ITEM)
|
||||
if (TextUtils.equals(dataBean!!.user!!.id, postListItemBean.authorId) || TextUtils.equals(dataBean!!.user!!.id, dataBean!!.thread!!.author!!.id)) {
|
||||
menu.findItem(R.id.menu_delete).isVisible = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,27 +3,22 @@ package com.huanchengfly.tieba.post.components.spans;
|
|||
import android.content.Context;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.huanchengfly.tieba.post.R;
|
||||
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils;
|
||||
import com.huanchengfly.tieba.post.utils.NavigationHelper;
|
||||
import com.huanchengfly.tieba.post.utils.UtilsKt;
|
||||
|
||||
public class MyURLSpan extends ClickableSpan {
|
||||
public String url;
|
||||
private Context context;
|
||||
private NavigationHelper navigationHelper;
|
||||
|
||||
public MyURLSpan(Context context, String url) {
|
||||
super();
|
||||
Log.i("MyURLSpan", "MyURLSpan: " + url);
|
||||
this.url = url;
|
||||
this.context = context;
|
||||
this.navigationHelper = NavigationHelper.newInstance(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -4,19 +4,29 @@ import android.content.Context
|
|||
import com.huanchengfly.tieba.post.plugins.PluginMenuItem.ClickCallback
|
||||
import com.huanchengfly.tieba.post.plugins.interfaces.IApp
|
||||
import com.huanchengfly.tieba.post.plugins.models.PluginManifest
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
abstract class IPlugin(
|
||||
val app: IApp,
|
||||
val manifest: PluginManifest
|
||||
) {
|
||||
) : CoroutineScope {
|
||||
val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Main + job
|
||||
|
||||
val context: Context
|
||||
get() = app.getAppContext()
|
||||
get() = app.getCurrentContext()
|
||||
|
||||
open fun onCreate() {}
|
||||
|
||||
open fun onEnable() {}
|
||||
|
||||
open fun onDisable() {}
|
||||
open fun onDisable() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
open fun onDestroy() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import android.content.Context
|
|||
import android.content.SharedPreferences
|
||||
import android.view.Menu
|
||||
import com.huanchengfly.tieba.post.api.models.ProfileBean
|
||||
import com.huanchengfly.tieba.post.api.models.SubFloorListBean
|
||||
import com.huanchengfly.tieba.post.api.models.ThreadContentBean
|
||||
import com.huanchengfly.tieba.post.fromJson
|
||||
import com.huanchengfly.tieba.post.plugins.interfaces.IApp
|
||||
import com.huanchengfly.tieba.post.plugins.models.BuiltInPlugins
|
||||
|
|
@ -15,6 +17,8 @@ import kotlin.reflect.KClass
|
|||
|
||||
object PluginManager {
|
||||
const val MENU_USER_ACTIVITY = "user_activity"
|
||||
const val MENU_POST_ITEM = "post_item"
|
||||
const val MENU_SUB_POST_ITEM = "sub_post_item"
|
||||
const val MENU_NONE = "none"
|
||||
|
||||
lateinit var appInstance: IApp
|
||||
|
|
@ -37,6 +41,8 @@ object PluginManager {
|
|||
registeredPluginMenuItems.clear()
|
||||
listOf(
|
||||
MENU_USER_ACTIVITY,
|
||||
MENU_POST_ITEM,
|
||||
MENU_SUB_POST_ITEM,
|
||||
MENU_NONE
|
||||
).forEach {
|
||||
registeredPluginMenuItems[it] = mutableMapOf()
|
||||
|
|
@ -56,7 +62,7 @@ object PluginManager {
|
|||
fun initPluginMenu(menu: Menu, menuId: String) {
|
||||
val menuItems = registeredPluginMenuItems[menuId]!!
|
||||
menuItems.forEach {
|
||||
menu.add(0, it.key, 0, it.value.title)
|
||||
menu.add(0, it.key, 100, it.value.title)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -196,6 +202,8 @@ fun getMenuByData(dataClass: KClass<*>): String = getMenuByData(dataClass.java)
|
|||
fun getMenuByData(dataClass: Class<*>): String {
|
||||
return when (dataClass.canonicalName) {
|
||||
ProfileBean::class.java.canonicalName -> PluginManager.MENU_USER_ACTIVITY
|
||||
ThreadContentBean.PostListItemBean::class.java.canonicalName -> PluginManager.MENU_POST_ITEM
|
||||
SubFloorListBean.PostInfo::class.java.canonicalName -> PluginManager.MENU_SUB_POST_ITEM
|
||||
else -> "none"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.huanchengfly.tieba.post.R;
|
||||
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils;
|
||||
import com.huanchengfly.tieba.post.utils.UtilsKt;
|
||||
|
||||
public class MyURLSpan extends ClickableSpan {
|
||||
public String url;
|
||||
private Context context;
|
||||
|
||||
public MyURLSpan(Context context, String url) {
|
||||
super();
|
||||
this.url = url;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(ThemeUtils.getColorByAttr(this.context, R.attr.colorAccent));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(@NonNull View view) {
|
||||
UtilsKt.launchUrl(context, url);
|
||||
//context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.view.View
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import com.huanchengfly.tieba.post.R
|
||||
import com.huanchengfly.tieba.post.api.models.ThreadContentBean
|
||||
import com.huanchengfly.tieba.post.components.LinkTouchMovementMethod
|
||||
import com.huanchengfly.tieba.post.components.spans.MyImageSpan
|
||||
import com.huanchengfly.tieba.post.plugins.IPlugin
|
||||
import com.huanchengfly.tieba.post.plugins.asoulcnki.api.CheckApi
|
||||
import com.huanchengfly.tieba.post.plugins.asoulcnki.models.CheckApiBody
|
||||
import com.huanchengfly.tieba.post.plugins.interfaces.IApp
|
||||
import com.huanchengfly.tieba.post.plugins.models.PluginManifest
|
||||
import com.huanchengfly.tieba.post.plugins.registerMenuItem
|
||||
import com.huanchengfly.tieba.post.toJson
|
||||
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils
|
||||
import com.huanchengfly.tieba.post.utils.DisplayUtil
|
||||
import com.huanchengfly.tieba.post.utils.Util
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.text.NumberFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class PluginAsoulCnki(app: IApp, manifest: PluginManifest) : IPlugin(app, manifest) {
|
||||
override fun onEnable() {
|
||||
super.onEnable()
|
||||
registerMenuItem<ThreadContentBean.PostListItemBean>(
|
||||
"asoul_cnki_check",
|
||||
context.getString(R.string.plugin_asoul_cnki_check)
|
||||
) { data ->
|
||||
val dialog = app.showLoadingDialog()
|
||||
val body = CheckApiBody(getPostTextContent(data)).toJson()
|
||||
launch(Dispatchers.IO + job) {
|
||||
val result =
|
||||
CheckApi.instance.checkAsync(body.toRequestBody("application/json, charset=utf-8".toMediaTypeOrNull()))
|
||||
.await()
|
||||
launch(Dispatchers.Main + job) {
|
||||
dialog.cancel()
|
||||
if (result.code == 0) {
|
||||
val numberFormatter = NumberFormat.getNumberInstance().apply {
|
||||
maximumFractionDigits = 2
|
||||
minimumFractionDigits = 2
|
||||
}
|
||||
app.showAlertDialog {
|
||||
setTitle("查重结果")
|
||||
val percent = "${numberFormatter.format(result.data.rate * 100.0)}%"
|
||||
val resultForCopy = context.getString(
|
||||
R.string.plugin_asoul_cnki_result,
|
||||
formatDateTime("yyyy-MM-dd HH:mm:ss"),
|
||||
percent,
|
||||
if (result.data.related.isNotEmpty()) {
|
||||
context.getString(
|
||||
R.string.plugin_asoul_cnki_related,
|
||||
result.data.related[0].replyUrl,
|
||||
result.data.related[0].reply.mName,
|
||||
formatDateTime(
|
||||
"yyyy-MM-dd HH:mm",
|
||||
result.data.related[0].reply.ctime * 1000L
|
||||
)
|
||||
)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
)
|
||||
val view = View.inflate(
|
||||
context,
|
||||
R.layout.plugin_asoul_cnki_dialog_check_result,
|
||||
null
|
||||
)
|
||||
val percentView = view.findViewById<TextView>(R.id.check_result_percent)
|
||||
val progress =
|
||||
view.findViewById<ProgressBar>(R.id.check_result_progress)
|
||||
val relatedView = view.findViewById<View>(R.id.check_result_related)
|
||||
val relatedTitle =
|
||||
view.findViewById<TextView>(R.id.check_result_related_title)
|
||||
val relatedContent =
|
||||
view.findViewById<TextView>(R.id.check_result_related_content)
|
||||
percentView.text = context.getString(
|
||||
R.string.plugin_asoul_cnki_check_result_percent,
|
||||
percent
|
||||
)
|
||||
progress.progress = (result.data.rate * 10000).toInt()
|
||||
if (result.data.related.isNullOrEmpty()) {
|
||||
relatedView.visibility = View.GONE
|
||||
} else {
|
||||
relatedView.visibility = View.VISIBLE
|
||||
relatedTitle.text = context.getString(
|
||||
R.string.plugin_asoul_cnki_check_result_related,
|
||||
result.data.related.size
|
||||
)
|
||||
}
|
||||
val relatedContentText = SpannableStringBuilder()
|
||||
result.data.related.forEach {
|
||||
relatedContentText.appendLink("${it.reply.mName} 的评论", it.replyUrl)
|
||||
.append("\n")
|
||||
}
|
||||
relatedContent.apply {
|
||||
text = relatedContentText
|
||||
movementMethod = LinkTouchMovementMethod.getInstance()
|
||||
}
|
||||
setView(view)
|
||||
setPositiveButton(R.string.btn_copy_check_result) { _, _ ->
|
||||
app.copyText(resultForCopy)
|
||||
}
|
||||
setNegativeButton(R.string.btn_close, null)
|
||||
}
|
||||
} else {
|
||||
app.toastShort("查重失败 ${result.code}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SpannableStringBuilder.appendLink(
|
||||
text: CharSequence,
|
||||
url: String
|
||||
): SpannableStringBuilder {
|
||||
val spannableStringBuilder = SpannableStringBuilder()
|
||||
val size = DisplayUtil.sp2px(context, 14f)
|
||||
val bitmap = Util.tintBitmap(
|
||||
Bitmap.createScaledBitmap(
|
||||
Util.getBitmapFromVectorDrawable(
|
||||
context,
|
||||
R.drawable.ic_link
|
||||
),
|
||||
size,
|
||||
size,
|
||||
true
|
||||
),
|
||||
ThemeUtils.getColorByAttr(context, R.attr.colorAccent)
|
||||
)
|
||||
spannableStringBuilder.append(
|
||||
"[链接]",
|
||||
MyImageSpan(context, bitmap),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
spannableStringBuilder.append(" ")
|
||||
spannableStringBuilder.append(
|
||||
text,
|
||||
MyURLSpan(context, url),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
return append(spannableStringBuilder)
|
||||
}
|
||||
|
||||
fun getPostTextContent(item: ThreadContentBean.PostListItemBean): String {
|
||||
val stringBuilder = StringBuilder()
|
||||
for (contentBean in item.content!!) {
|
||||
when (contentBean.type) {
|
||||
"2" -> contentBean.setText("#(" + contentBean.c + ")")
|
||||
"3", "20" -> contentBean.setText("[图片]\n")
|
||||
"10" -> contentBean.setText("[语音]\n")
|
||||
}
|
||||
if (contentBean.text != null) {
|
||||
stringBuilder.append(contentBean.text)
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
private fun formatDateTime(
|
||||
pattern: String,
|
||||
timestamp: Long = System.currentTimeMillis()
|
||||
): String {
|
||||
return SimpleDateFormat(pattern, Locale.getDefault()).format(Date(timestamp))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.api
|
||||
|
||||
import com.huanchengfly.tieba.post.api.retrofit.NullOnEmptyConverterFactory
|
||||
import com.huanchengfly.tieba.post.api.retrofit.adapter.DeferredCallAdapterFactory
|
||||
import com.huanchengfly.tieba.post.api.retrofit.converter.gson.GsonConverterFactory
|
||||
import okhttp3.ConnectionPool
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
|
||||
object CheckApi {
|
||||
private val connectionPool = ConnectionPool()
|
||||
|
||||
val instance: ICheckApi by lazy {
|
||||
Retrofit.Builder()
|
||||
.baseUrl("https://asoulcnki.asia/")
|
||||
.addCallAdapterFactory(DeferredCallAdapterFactory())
|
||||
.addConverterFactory(NullOnEmptyConverterFactory())
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.client(OkHttpClient.Builder().apply {
|
||||
connectionPool(connectionPool)
|
||||
}.build())
|
||||
.build()
|
||||
.create(ICheckApi::class.java)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.api
|
||||
|
||||
import com.huanchengfly.tieba.post.api.ParamExpression
|
||||
import com.huanchengfly.tieba.post.api.forEachNonNull
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
class CommonHeaderInterceptor(private vararg val additionHeaders: ParamExpression) : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
val headers = request.headers
|
||||
|
||||
return chain.proceed(request.newBuilder().apply {
|
||||
additionHeaders.forEachNonNull { name, value ->
|
||||
if (headers[name] == null) addHeader(name, value)
|
||||
}
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.api
|
||||
|
||||
import com.huanchengfly.tieba.post.plugins.asoulcnki.models.CheckResult
|
||||
import kotlinx.coroutines.Deferred
|
||||
import okhttp3.RequestBody
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface ICheckApi {
|
||||
@POST("/v1/api/check")
|
||||
@Headers("content-type: application/json;charset=UTF-8")
|
||||
fun checkAsync(
|
||||
@Body requestBody: RequestBody
|
||||
): Deferred<CheckResult>
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.models
|
||||
|
||||
data class CheckApiBody(
|
||||
val text: String
|
||||
)
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.huanchengfly.tieba.post.plugins.asoulcnki.models
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
data class CheckResult(
|
||||
val code: Int, // 0
|
||||
val `data`: Data,
|
||||
val message: String // success
|
||||
) {
|
||||
@Keep
|
||||
data class Data(
|
||||
@SerializedName("end_time")
|
||||
val endTime: Int, // 1629010807
|
||||
val rate: Double, // 1.0
|
||||
val related: List<Related>,
|
||||
@SerializedName("start_time")
|
||||
val startTime: Int // 1606137506
|
||||
) {
|
||||
@Keep
|
||||
data class Related(
|
||||
val rate: Double, // 1.0
|
||||
val reply: Reply,
|
||||
@SerializedName("reply_url")
|
||||
val replyUrl: String // https://www.bilibili.com/video/av377092608/#reply5051494613
|
||||
) {
|
||||
@Keep
|
||||
data class Reply(
|
||||
val content: String, // 曾几何时,我也想像asoul的beeeeeeeela一样做幸福滤镜下的事至少在这层滤镜下,beeeeeeeela的一举一动都是随心所欲且浪漫真实的当我看到beeeeeeeela能像个二次元一样和弹幕大谈特谈50音,当我看到beeeeeeeela能够笑着在夜里唱着不知道练了多少遍的云烟成雨,当我看到她可以在失落后得到安抚和拥抱…以往的笑意消散殆尽,剩下的只有我对beeeeeeeela浪漫的感动和一种无中生有的失意了。我也想像她一样。但这是虚假的,每次在烂醉酩酊起来后依然会痛苦,每次在浪费时间的时候都能意识到,你不能感受到我感受到的东西。但就算是这样,没了你我可能就会完蛋了吧。因为我们需要一个梦。
|
||||
val ctime: Int, // 1627881576
|
||||
@SerializedName("dynamic_id")
|
||||
val dynamicId: String, // 553473662133564230
|
||||
@SerializedName("like_num")
|
||||
val likeNum: Int, // 9
|
||||
@SerializedName("m_name")
|
||||
val mName: String, // 走出童年
|
||||
val mid: Int, // 671239951
|
||||
val oid: String, // 377092608
|
||||
@SerializedName("origin_rpid")
|
||||
val originRpid: String, // -1
|
||||
val rpid: String, // 5051494613
|
||||
@SerializedName("similar_count")
|
||||
val similarCount: Int, // 1
|
||||
@SerializedName("similar_like_sum")
|
||||
val similarLikeSum: Int, // 424
|
||||
@SerializedName("type_id")
|
||||
val typeId: Int, // 1
|
||||
val uid: Int // 672346917
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,21 @@
|
|||
package com.huanchengfly.tieba.post.plugins.interfaces
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
|
||||
interface IApp {
|
||||
fun getAppContext(): Context
|
||||
|
||||
fun getCurrentContext(): Context
|
||||
|
||||
fun launchUrl(url: String)
|
||||
|
||||
fun showLoadingDialog(): Dialog
|
||||
|
||||
fun toastShort(text: String)
|
||||
|
||||
fun copyText(text: String)
|
||||
|
||||
fun showAlertDialog(builder: AlertDialog.Builder.() -> Unit): AlertDialog
|
||||
}
|
||||
Loading…
Reference in New Issue