优化:企微群机器人发送通道支持Markdown格式消息 #292

This commit is contained in:
pppscn 2023-05-07 14:21:40 +08:00
parent c7ead43a29
commit 862477e15c
6 changed files with 404 additions and 343 deletions

View File

@ -1,7 +1,18 @@
package com.idormy.sms.forwarder.entity.setting package com.idormy.sms.forwarder.entity.setting
import com.idormy.sms.forwarder.R
import java.io.Serializable import java.io.Serializable
data class WeworkRobotSetting( data class WeworkRobotSetting(
var webHook: String, var webHook: String,
) : Serializable val msgType: String = "text",
) : Serializable {
fun getMsgTypeCheckId(): Int {
return if (msgType == "markdown") {
R.id.rb_msg_type_markdown
} else {
R.id.rb_msg_type_text
}
}
}

View File

@ -1,215 +1,218 @@
package com.idormy.sms.forwarder.fragment.senders package com.idormy.sms.forwarder.fragment.senders
import android.os.Looper import android.os.Looper
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import com.google.gson.Gson import com.google.gson.Gson
import com.idormy.sms.forwarder.R import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.database.entity.Sender import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
import com.idormy.sms.forwarder.databinding.FragmentSendersWeworkRobotBinding import com.idormy.sms.forwarder.databinding.FragmentSendersWeworkRobotBinding
import com.idormy.sms.forwarder.entity.MsgInfo import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.setting.WeworkRobotSetting import com.idormy.sms.forwarder.entity.setting.WeworkRobotSetting
import com.idormy.sms.forwarder.utils.* import com.idormy.sms.forwarder.utils.*
import com.idormy.sms.forwarder.utils.sender.WeworkRobotUtils import com.idormy.sms.forwarder.utils.sender.WeworkRobotUtils
import com.jeremyliao.liveeventbus.LiveEventBus import com.jeremyliao.liveeventbus.LiveEventBus
import com.xuexiang.xaop.annotation.SingleClick import com.xuexiang.xaop.annotation.SingleClick
import com.xuexiang.xpage.annotation.Page import com.xuexiang.xpage.annotation.Page
import com.xuexiang.xrouter.annotation.AutoWired import com.xuexiang.xrouter.annotation.AutoWired
import com.xuexiang.xrouter.launcher.XRouter import com.xuexiang.xrouter.launcher.XRouter
import com.xuexiang.xui.utils.CountDownButtonHelper import com.xuexiang.xui.utils.CountDownButtonHelper
import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.actionbar.TitleBar
import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction
import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog
import io.reactivex.SingleObserver import io.reactivex.SingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.util.* import java.util.*
@Page(name = "企业微信群机器人") @Page(name = "企业微信群机器人")
@Suppress("PrivatePropertyName") @Suppress("PrivatePropertyName")
class WeworkRobotFragment : BaseFragment<FragmentSendersWeworkRobotBinding?>(), View.OnClickListener { class WeworkRobotFragment : BaseFragment<FragmentSendersWeworkRobotBinding?>(), View.OnClickListener {
private val TAG: String = WeworkRobotFragment::class.java.simpleName private val TAG: String = WeworkRobotFragment::class.java.simpleName
var titleBar: TitleBar? = null var titleBar: TitleBar? = null
private val viewModel by viewModels<SenderViewModel> { BaseViewModelFactory(context) } private val viewModel by viewModels<SenderViewModel> { BaseViewModelFactory(context) }
private var mCountDownHelper: CountDownButtonHelper? = null private var mCountDownHelper: CountDownButtonHelper? = null
@JvmField @JvmField
@AutoWired(name = KEY_SENDER_ID) @AutoWired(name = KEY_SENDER_ID)
var senderId: Long = 0 var senderId: Long = 0
@JvmField @JvmField
@AutoWired(name = KEY_SENDER_TYPE) @AutoWired(name = KEY_SENDER_TYPE)
var senderType: Int = 0 var senderType: Int = 0
@JvmField @JvmField
@AutoWired(name = KEY_SENDER_CLONE) @AutoWired(name = KEY_SENDER_CLONE)
var isClone: Boolean = false var isClone: Boolean = false
override fun initArgs() { override fun initArgs() {
XRouter.getInstance().inject(this) XRouter.getInstance().inject(this)
} }
override fun viewBindingInflate( override fun viewBindingInflate(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup, container: ViewGroup,
): FragmentSendersWeworkRobotBinding { ): FragmentSendersWeworkRobotBinding {
return FragmentSendersWeworkRobotBinding.inflate(inflater, container, false) return FragmentSendersWeworkRobotBinding.inflate(inflater, container, false)
} }
override fun initTitle(): TitleBar? { override fun initTitle(): TitleBar? {
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.wework_robot) titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.wework_robot)
return titleBar return titleBar
} }
/** /**
* 初始化控件 * 初始化控件
*/ */
override fun initViews() { override fun initViews() {
//测试按钮增加倒计时,避免重复点击 //测试按钮增加倒计时,避免重复点击
mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, SettingUtils.requestTimeout) mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, SettingUtils.requestTimeout)
mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener { mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener {
override fun onCountDown(time: Int) { override fun onCountDown(time: Int) {
binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time) binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time)
} }
override fun onFinished() { override fun onFinished() {
binding!!.btnTest.text = getString(R.string.test) binding!!.btnTest.text = getString(R.string.test)
} }
}) })
//新增 //新增
if (senderId <= 0) { if (senderId <= 0) {
titleBar?.setSubTitle(getString(R.string.add_sender)) titleBar?.setSubTitle(getString(R.string.add_sender))
binding!!.btnDel.setText(R.string.discard) binding!!.btnDel.setText(R.string.discard)
return return
} }
//编辑 //编辑
binding!!.btnDel.setText(R.string.del) binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext()) AppDatabase.getInstance(requireContext())
.senderDao() .senderDao()
.get(senderId) .get(senderId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> { .subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {} override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
e.printStackTrace() e.printStackTrace()
} }
override fun onSuccess(sender: Sender) { override fun onSuccess(sender: Sender) {
if (isClone) { if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name) titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard) binding!!.btnDel.setText(R.string.discard)
} else { } else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name) titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
} }
binding!!.etName.setText(sender.name) binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1 binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, WeworkRobotSetting::class.java) val settingVo = Gson().fromJson(sender.jsonSetting, WeworkRobotSetting::class.java)
Log.d(TAG, settingVo.toString()) Log.d(TAG, settingVo.toString())
if (settingVo != null) { if (settingVo != null) {
binding!!.etWebHook.setText(settingVo.webHook) binding!!.etWebHook.setText(settingVo.webHook)
} binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
} }
}) }
} })
}
override fun initListeners() {
binding!!.btnTest.setOnClickListener(this) override fun initListeners() {
binding!!.btnDel.setOnClickListener(this) binding!!.btnTest.setOnClickListener(this)
binding!!.btnSave.setOnClickListener(this) binding!!.btnDel.setOnClickListener(this)
LiveEventBus.get(KEY_SENDER_TEST, String::class.java).observe(this) { mCountDownHelper?.finish() } binding!!.btnSave.setOnClickListener(this)
} LiveEventBus.get(KEY_SENDER_TEST, String::class.java).observe(this) { mCountDownHelper?.finish() }
}
@SingleClick
override fun onClick(v: View) { @SingleClick
try { override fun onClick(v: View) {
when (v.id) { try {
R.id.btn_test -> { when (v.id) {
mCountDownHelper?.start() R.id.btn_test -> {
Thread { mCountDownHelper?.start()
try { Thread {
val settingVo = checkSetting() try {
Log.d(TAG, settingVo.toString()) val settingVo = checkSetting()
val msgInfo = MsgInfo("sms", getString(R.string.test_phone_num), getString(R.string.test_sender_sms), Date(), getString(R.string.test_sim_info)) Log.d(TAG, settingVo.toString())
WeworkRobotUtils.sendMsg(settingVo, msgInfo) val msgInfo = MsgInfo("sms", getString(R.string.test_phone_num), getString(R.string.test_sender_sms), Date(), getString(R.string.test_sim_info))
} catch (e: Exception) { WeworkRobotUtils.sendMsg(settingVo, msgInfo)
e.printStackTrace() } catch (e: Exception) {
if (Looper.myLooper() == null) Looper.prepare() e.printStackTrace()
XToastUtils.error(e.message.toString()) if (Looper.myLooper() == null) Looper.prepare()
Looper.loop() XToastUtils.error(e.message.toString())
} Looper.loop()
LiveEventBus.get(KEY_SENDER_TEST, String::class.java).post("finish") }
}.start() LiveEventBus.get(KEY_SENDER_TEST, String::class.java).post("finish")
return }.start()
} return
R.id.btn_del -> { }
if (senderId <= 0 || isClone) {
popToBack() R.id.btn_del -> {
return if (senderId <= 0 || isClone) {
} popToBack()
return
MaterialDialog.Builder(requireContext()) }
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips) MaterialDialog.Builder(requireContext())
.positiveText(R.string.lab_yes) .title(R.string.delete_sender_title)
.negativeText(R.string.lab_no) .content(R.string.delete_sender_tips)
.onPositive { _: MaterialDialog?, _: DialogAction? -> .positiveText(R.string.lab_yes)
viewModel.delete(senderId) .negativeText(R.string.lab_no)
XToastUtils.success(R.string.delete_sender_toast) .onPositive { _: MaterialDialog?, _: DialogAction? ->
popToBack() viewModel.delete(senderId)
} XToastUtils.success(R.string.delete_sender_toast)
.show() popToBack()
return }
} .show()
R.id.btn_save -> { return
val name = binding!!.etName.text.toString().trim() }
if (TextUtils.isEmpty(name)) {
throw Exception(getString(R.string.invalid_name)) R.id.btn_save -> {
} val name = binding!!.etName.text.toString().trim()
if (TextUtils.isEmpty(name)) {
val status = if (binding!!.sbEnable.isChecked) 1 else 0 throw Exception(getString(R.string.invalid_name))
val settingVo = checkSetting() }
if (isClone) senderId = 0
val senderNew = Sender(senderId, senderType, name, Gson().toJson(settingVo), status) val status = if (binding!!.sbEnable.isChecked) 1 else 0
Log.d(TAG, senderNew.toString()) val settingVo = checkSetting()
if (isClone) senderId = 0
viewModel.insertOrUpdate(senderNew) val senderNew = Sender(senderId, senderType, name, Gson().toJson(settingVo), status)
XToastUtils.success(R.string.tipSaveSuccess) Log.d(TAG, senderNew.toString())
popToBack()
return viewModel.insertOrUpdate(senderNew)
} XToastUtils.success(R.string.tipSaveSuccess)
} popToBack()
} catch (e: Exception) { return
XToastUtils.error(e.message.toString()) }
e.printStackTrace() }
} } catch (e: Exception) {
} XToastUtils.error(e.message.toString())
e.printStackTrace()
private fun checkSetting(): WeworkRobotSetting { }
val webHook = binding!!.etWebHook.text.toString().trim() }
if (!CommonUtils.checkUrl(webHook, false)) {
throw Exception(getString(R.string.invalid_webhook)) private fun checkSetting(): WeworkRobotSetting {
} val webHook = binding!!.etWebHook.text.toString().trim()
if (!CommonUtils.checkUrl(webHook, false)) {
return WeworkRobotSetting(webHook) throw Exception(getString(R.string.invalid_webhook))
} }
val msgType = if (binding!!.rgMsgType.checkedRadioButtonId == R.id.rb_msg_type_markdown) "markdown" else "text"
override fun onDestroyView() { return WeworkRobotSetting(webHook, msgType)
if (mCountDownHelper != null) mCountDownHelper!!.recycle() }
super.onDestroyView()
} override fun onDestroyView() {
if (mCountDownHelper != null) mCountDownHelper!!.recycle()
super.onDestroyView()
}
} }

View File

@ -13,7 +13,6 @@ import com.xuexiang.xhttp2.cache.model.CacheMode
import com.xuexiang.xhttp2.callback.SimpleCallBack import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException import com.xuexiang.xhttp2.exception.ApiException
@Suppress("PrivatePropertyName", "UNUSED_PARAMETER")
class WeworkRobotUtils private constructor() { class WeworkRobotUtils private constructor() {
companion object { companion object {
@ -37,11 +36,17 @@ class WeworkRobotUtils private constructor() {
Log.i(TAG, "requestUrl:$requestUrl") Log.i(TAG, "requestUrl:$requestUrl")
val msgMap: MutableMap<String, Any> = mutableMapOf() val msgMap: MutableMap<String, Any> = mutableMapOf()
msgMap["msgtype"] = "text" msgMap["msgtype"] = setting.msgType
val textText: MutableMap<String, Any> = mutableMapOf() if (setting.msgType == "markdown") {
textText["content"] = content val markdownText: MutableMap<String, Any> = mutableMapOf()
msgMap["text"] = textText markdownText["content"] = content
msgMap["markdown"] = markdownText
} else {
val textText: MutableMap<String, Any> = mutableMapOf()
textText["content"] = content
msgMap["text"] = textText
}
val requestMsg: String = Gson().toJson(msgMap) val requestMsg: String = Gson().toJson(msgMap)
Log.i(TAG, "requestMsg:$requestMsg") Log.i(TAG, "requestMsg:$requestMsg")

View File

@ -1,122 +1,158 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/xui_config_color_background" android:background="?attr/xui_config_color_background"
android:orientation="vertical"> android:orientation="vertical">
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:overScrollMode="never"> android:overScrollMode="never">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="5dp" android:layout_margin="5dp"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <LinearLayout
style="@style/senderBarStyleWithSwitch" style="@style/senderBarStyleWithSwitch"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/sender_name_status" android:text="@string/sender_name_status"
android:textStyle="bold" /> android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText <com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_name" android:id="@+id/et_name"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:layout_weight="1" android:layout_weight="1"
android:singleLine="true" android:singleLine="true"
app:met_clearButton="true" /> app:met_clearButton="true" />
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton <com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_enable" android:id="@+id/sb_enable"
style="@style/SwitchButtonStyle" style="@style/SwitchButtonStyle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="true" /> android:checked="true" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
style="@style/senderBarStyle" style="@style/senderBarStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/wework_webHook" android:text="@string/wework_webHook"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/wework_webHook_tips" android:text="@string/wework_webHook_tips"
android:textSize="10sp" android:textSize="10sp"
tools:ignore="SmallSp" /> tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText <com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_webHook" android:id="@+id/et_webHook"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:singleLine="true" android:singleLine="true"
app:met_passWordButton="true" /> app:met_passWordButton="true" />
</LinearLayout> </LinearLayout>
</LinearLayout> <LinearLayout
style="@style/senderBarStyle"
</androidx.core.widget.NestedScrollView> android:layout_width="match_parent"
android:layout_height="wrap_content"
<LinearLayout android:orientation="horizontal">
android:layout_width="match_parent"
android:layout_height="wrap_content" <TextView
android:gravity="center" android:layout_width="wrap_content"
android:orientation="horizontal" android:layout_height="wrap_content"
android:padding="10dp"> android:text="@string/wework_msg_type"
android:textStyle="bold" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_del" <RadioGroup
style="@style/SuperButton.Gray.Icon" android:id="@+id/rg_msg_type"
android:drawableStart="@drawable/icon_delete" android:layout_width="wrap_content"
android:paddingStart="15dp" android:layout_height="wrap_content"
android:text="@string/del" android:layout_marginStart="3dp"
android:textSize="11sp" android:orientation="horizontal">
tools:ignore="RtlSymmetry" />
<RadioButton
<com.xuexiang.xui.widget.textview.supertextview.SuperButton android:id="@+id/rb_msg_type_text"
android:id="@+id/btn_save" android:layout_width="wrap_content"
style="@style/SuperButton.Blue.Icon" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:checked="true"
android:drawableStart="@drawable/icon_save" android:text="@string/wework_msg_type_text" />
android:paddingStart="15dp"
android:text="@string/save" <RadioButton
android:textSize="11sp" android:id="@+id/rb_msg_type_markdown"
tools:ignore="RtlSymmetry" /> android:layout_width="wrap_content"
android:layout_height="wrap_content"
<com.xuexiang.xui.widget.textview.supertextview.SuperButton android:text="@string/wework_msg_type_markdown" />
android:id="@+id/btn_test"
style="@style/SuperButton.Green.Icon" </RadioGroup>
android:layout_marginStart="10dp"
android:drawableStart="@drawable/icon_test" </LinearLayout>
android:paddingStart="15dp"
android:text="@string/test" </LinearLayout>
android:textSize="11sp"
tools:ignore="RtlSymmetry" /> </androidx.core.widget.NestedScrollView>
</LinearLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp">
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_del"
style="@style/SuperButton.Gray.Icon"
android:drawableStart="@drawable/icon_delete"
android:paddingStart="15dp"
android:text="@string/del"
android:textSize="11sp"
tools:ignore="RtlSymmetry" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_save"
style="@style/SuperButton.Blue.Icon"
android:layout_marginStart="10dp"
android:drawableStart="@drawable/icon_save"
android:paddingStart="15dp"
android:text="@string/save"
android:textSize="11sp"
tools:ignore="RtlSymmetry" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_test"
style="@style/SuperButton.Green.Icon"
android:layout_marginStart="10dp"
android:drawableStart="@drawable/icon_test"
android:paddingStart="15dp"
android:text="@string/test"
android:textSize="11sp"
tools:ignore="RtlSymmetry" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -559,10 +559,10 @@
<string name="keep_alive_tips">It is recommended to open the first three switch, do not disable the notification bar, to avoid APP being killed</string> <string name="keep_alive_tips">It is recommended to open the first three switch, do not disable the notification bar, to avoid APP being killed</string>
<string name="custom_settings">Custom Settings</string> <string name="custom_settings">Custom Settings</string>
<string name="custom_settings_tips">Please fill in the remarks manually or click the refresh button to get it automatically</string> <string name="custom_settings_tips">Please fill in the remarks manually or click the refresh button to get it automatically</string>
<string name="times">,</string> <string name="times">times</string>
<string name="interval">Interval</string> <string name="interval">Interval</string>
<string name="timeout">Timeout</string> <string name="timeout">Timeout</string>
<string name="seconds">s</string> <string name="seconds">secs</string>
<string name="seconds_n">%s sec</string> <string name="seconds_n">%s sec</string>
<string name="retry">Retry</string> <string name="retry">Retry</string>
<string name="test_sender_sms">[Test Channel] Congratulations, the sending channel test is successful, please continue to add forwarding rules!</string> <string name="test_sender_sms">[Test Channel] Congratulations, the sending channel test is successful, please continue to add forwarding rules!</string>
@ -743,6 +743,9 @@
<string name="wework_webHook">WebHook</string> <string name="wework_webHook">WebHook</string>
<string name="wework_webHook_tips">Example: https://qyapi.weixin.qq.com/cgixx?key=xxx</string> <string name="wework_webHook_tips">Example: https://qyapi.weixin.qq.com/cgixx?key=xxx</string>
<string name="wework_msg_type">Msg Type</string>
<string name="wework_msg_type_text">Text</string>
<string name="wework_msg_type_markdown">Markdown</string>
<string name="url_scheme">URL Scheme</string> <string name="url_scheme">URL Scheme</string>
<string name="url_scheme_tips">Examplemyapp://api/add?&amp;type=0&amp;msg=[msg]</string> <string name="url_scheme_tips">Examplemyapp://api/add?&amp;type=0&amp;msg=[msg]</string>

View File

@ -744,6 +744,9 @@
<string name="wework_webHook">WebHook地址</string> <string name="wework_webHook">WebHook地址</string>
<string name="wework_webHook_tips">示例https://qyapi.weixin.qq.com/cgixx?key=xxx</string> <string name="wework_webHook_tips">示例https://qyapi.weixin.qq.com/cgixx?key=xxx</string>
<string name="wework_msg_type">消息类型</string>
<string name="wework_msg_type_text">纯文本</string>
<string name="wework_msg_type_markdown">markdown</string>
<string name="url_scheme">URL Scheme</string> <string name="url_scheme">URL Scheme</string>
<string name="url_scheme_tips">示例myapp://api/add?&amp;type=0&amp;msg=[msg]</string> <string name="url_scheme_tips">示例myapp://api/add?&amp;type=0&amp;msg=[msg]</string>