新增:`飞书企业应用`发送通道
This commit is contained in:
parent
84d321dba8
commit
17df392ae4
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
短信转发器——不仅只转发短信,备用机必备神器!
|
短信转发器——不仅只转发短信,备用机必备神器!
|
||||||
|
|
||||||
监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉群自定义机器人、钉钉企业内机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。
|
监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉群自定义机器人、钉钉企业内机器人、企业微信群机器人、企业微信应用消息、飞书群机器人、飞书企业应用、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。
|
||||||
|
|
||||||
包括主动控制服务端与客户端,让你轻松远程发短信、查短信、查通话、查话簿、查电量等。(V3.0 新增)
|
包括主动控制服务端与客户端,让你轻松远程发短信、查短信、查通话、查话簿、查电量等。(V3.0 新增)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
SmsForwarder - Not only forwarding text messages, but also a must-have for backup devices!
|
SmsForwarder - Not only forwarding text messages, but also a must-have for backup devices!
|
||||||
|
|
||||||
listens to SMS, incoming calls, and App notifications on Android mobile devices, and forward according to user defined rules to another App/device, including DingTalk, WeCom and WeCom Group Bot, Feishi Bot, E-mail, Bark, Webhook, Telegram Bot, ServerChan, PushPlus, SMS, etc.
|
listens to SMS, incoming calls, and App notifications on Android mobile devices, and forward according to user defined rules to another App/device, including DingTalk, WeCom and WeCom Group Bot, Feishu App and Feishu Group Bot, E-mail, Bark, Webhook, Telegram Bot, ServerChan, PushPlus, SMS, etc.
|
||||||
|
|
||||||
Including active control of the server and client, allowing you to easily and remotely send text messages, check text messages, check calls, check the phone book, check the battery, etc.
|
Including active control of the server and client, allowing you to easily and remotely send text messages, check text messages, check calls, check the phone book, check the battery, etc.
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ data class Sender(
|
||||||
TYPE_GOTIFY -> R.drawable.icon_gotify
|
TYPE_GOTIFY -> R.drawable.icon_gotify
|
||||||
TYPE_SMS -> R.drawable.icon_sms
|
TYPE_SMS -> R.drawable.icon_sms
|
||||||
TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner
|
TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner
|
||||||
|
TYPE_FEISHU_APP -> R.drawable.icon_feishu_app
|
||||||
else -> R.drawable.icon_sms
|
else -> R.drawable.icon_sms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ data class Sender(
|
||||||
TYPE_GOTIFY -> R.drawable.icon_gotify
|
TYPE_GOTIFY -> R.drawable.icon_gotify
|
||||||
TYPE_SMS -> R.drawable.icon_sms
|
TYPE_SMS -> R.drawable.icon_sms
|
||||||
TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner
|
TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner
|
||||||
|
TYPE_FEISHU_APP -> R.drawable.icon_feishu_app
|
||||||
else -> R.drawable.icon_sms
|
else -> R.drawable.icon_sms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.idormy.sms.forwarder.entity.result
|
||||||
|
|
||||||
|
data class FeishuAppResult(
|
||||||
|
var code: Long,
|
||||||
|
var msg: String,
|
||||||
|
//获取access_token返回
|
||||||
|
var tenant_access_token: String?,
|
||||||
|
var expire: Long?,
|
||||||
|
//发送接口返回
|
||||||
|
var content: String?,
|
||||||
|
)
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.idormy.sms.forwarder.entity.setting
|
||||||
|
|
||||||
|
import com.idormy.sms.forwarder.R
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
data class FeishuAppSetting(
|
||||||
|
var appId: String = "",
|
||||||
|
val appSecret: String = "",
|
||||||
|
val receiveId: String = "",
|
||||||
|
val msgType: String = "interactive",
|
||||||
|
val titleTemplate: String = "",
|
||||||
|
) : Serializable {
|
||||||
|
|
||||||
|
fun getMsgTypeCheckId(): Int {
|
||||||
|
return if (msgType == null || msgType == "interactive") {
|
||||||
|
R.id.rb_msg_type_interactive
|
||||||
|
} else {
|
||||||
|
R.id.rb_msg_type_text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,6 +108,7 @@ class SendersFragment : BaseFragment<FragmentSendersBinding?>(), SenderPagingAda
|
||||||
TYPE_PUSHPLUS -> PushplusFragment::class.java
|
TYPE_PUSHPLUS -> PushplusFragment::class.java
|
||||||
TYPE_GOTIFY -> GotifyFragment::class.java
|
TYPE_GOTIFY -> GotifyFragment::class.java
|
||||||
TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java
|
TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java
|
||||||
|
TYPE_FEISHU_APP -> FeishuAppFragment::class.java
|
||||||
else -> DingtalkGroupRobotFragment::class.java
|
else -> DingtalkGroupRobotFragment::class.java
|
||||||
}
|
}
|
||||||
).setNewActivity(true)
|
).setNewActivity(true)
|
||||||
|
@ -132,6 +133,7 @@ class SendersFragment : BaseFragment<FragmentSendersBinding?>(), SenderPagingAda
|
||||||
TYPE_PUSHPLUS -> PushplusFragment::class.java
|
TYPE_PUSHPLUS -> PushplusFragment::class.java
|
||||||
TYPE_GOTIFY -> GotifyFragment::class.java
|
TYPE_GOTIFY -> GotifyFragment::class.java
|
||||||
TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java
|
TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java
|
||||||
|
TYPE_FEISHU_APP -> FeishuAppFragment::class.java
|
||||||
else -> DingtalkGroupRobotFragment::class.java
|
else -> DingtalkGroupRobotFragment::class.java
|
||||||
}
|
}
|
||||||
).setNewActivity(true)
|
).setNewActivity(true)
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
package com.idormy.sms.forwarder.fragment.senders
|
||||||
|
|
||||||
|
import android.os.Looper
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.EditText
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.idormy.sms.forwarder.R
|
||||||
|
import com.idormy.sms.forwarder.core.BaseFragment
|
||||||
|
import com.idormy.sms.forwarder.database.AppDatabase
|
||||||
|
import com.idormy.sms.forwarder.database.entity.Sender
|
||||||
|
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
|
||||||
|
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
|
||||||
|
import com.idormy.sms.forwarder.databinding.FragmentSendersFeishuAppBinding
|
||||||
|
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||||
|
import com.idormy.sms.forwarder.entity.setting.FeishuAppSetting
|
||||||
|
import com.idormy.sms.forwarder.utils.*
|
||||||
|
import com.idormy.sms.forwarder.utils.sender.FeishuAppUtils
|
||||||
|
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||||
|
import com.xuexiang.xaop.annotation.SingleClick
|
||||||
|
import com.xuexiang.xpage.annotation.Page
|
||||||
|
import com.xuexiang.xrouter.annotation.AutoWired
|
||||||
|
import com.xuexiang.xrouter.launcher.XRouter
|
||||||
|
import com.xuexiang.xui.utils.CountDownButtonHelper
|
||||||
|
import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||||
|
import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction
|
||||||
|
import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog
|
||||||
|
import io.reactivex.SingleObserver
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@Page(name = "飞书企业应用")
|
||||||
|
@Suppress("PrivatePropertyName")
|
||||||
|
class FeishuAppFragment : BaseFragment<FragmentSendersFeishuAppBinding?>(), View.OnClickListener {
|
||||||
|
|
||||||
|
private val TAG: String = FeishuAppFragment::class.java.simpleName
|
||||||
|
var titleBar: TitleBar? = null
|
||||||
|
private val viewModel by viewModels<SenderViewModel> { BaseViewModelFactory(context) }
|
||||||
|
private var mCountDownHelper: CountDownButtonHelper? = null
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
@AutoWired(name = KEY_SENDER_ID)
|
||||||
|
var senderId: Long = 0
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
@AutoWired(name = KEY_SENDER_TYPE)
|
||||||
|
var senderType: Int = 0
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
@AutoWired(name = KEY_SENDER_CLONE)
|
||||||
|
var isClone: Boolean = false
|
||||||
|
|
||||||
|
override fun initArgs() {
|
||||||
|
XRouter.getInstance().inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun viewBindingInflate(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup,
|
||||||
|
): FragmentSendersFeishuAppBinding {
|
||||||
|
return FragmentSendersFeishuAppBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initTitle(): TitleBar? {
|
||||||
|
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.feishu_app)
|
||||||
|
return titleBar
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化控件
|
||||||
|
*/
|
||||||
|
override fun initViews() {
|
||||||
|
//测试按钮增加倒计时,避免重复点击
|
||||||
|
mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, SettingUtils.requestTimeout)
|
||||||
|
mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener {
|
||||||
|
override fun onCountDown(time: Int) {
|
||||||
|
binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFinished() {
|
||||||
|
binding!!.btnTest.text = getString(R.string.test)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//新增
|
||||||
|
if (senderId <= 0) {
|
||||||
|
titleBar?.setSubTitle(getString(R.string.add_sender))
|
||||||
|
binding!!.btnDel.setText(R.string.discard)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//编辑
|
||||||
|
binding!!.btnDel.setText(R.string.del)
|
||||||
|
AppDatabase.getInstance(requireContext())
|
||||||
|
.senderDao()
|
||||||
|
.get(senderId)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(object : SingleObserver<Sender> {
|
||||||
|
override fun onSubscribe(d: Disposable) {}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(sender: Sender) {
|
||||||
|
if (isClone) {
|
||||||
|
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
|
||||||
|
binding!!.btnDel.setText(R.string.discard)
|
||||||
|
} else {
|
||||||
|
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
|
||||||
|
}
|
||||||
|
binding!!.etName.setText(sender.name)
|
||||||
|
binding!!.sbEnable.isChecked = sender.status == 1
|
||||||
|
val settingVo = Gson().fromJson(sender.jsonSetting, FeishuAppSetting::class.java)
|
||||||
|
Log.d(TAG, settingVo.toString())
|
||||||
|
if (settingVo != null) {
|
||||||
|
binding!!.etAppId.setText(settingVo.appId)
|
||||||
|
binding!!.etAppSecret.setText(settingVo.appSecret)
|
||||||
|
binding!!.etUserId.setText(settingVo.receiveId)
|
||||||
|
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
|
||||||
|
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initListeners() {
|
||||||
|
binding!!.btInsertSender.setOnClickListener(this)
|
||||||
|
binding!!.btInsertExtra.setOnClickListener(this)
|
||||||
|
binding!!.btInsertTime.setOnClickListener(this)
|
||||||
|
binding!!.btInsertDeviceName.setOnClickListener(this)
|
||||||
|
binding!!.btnTest.setOnClickListener(this)
|
||||||
|
binding!!.btnDel.setOnClickListener(this)
|
||||||
|
binding!!.btnSave.setOnClickListener(this)
|
||||||
|
LiveEventBus.get(KEY_SENDER_TEST, String::class.java).observe(this) { mCountDownHelper?.finish() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@SingleClick
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
try {
|
||||||
|
val etTitleTemplate: EditText = binding!!.etTitleTemplate
|
||||||
|
when (v.id) {
|
||||||
|
R.id.bt_insert_sender -> {
|
||||||
|
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_from))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
R.id.bt_insert_extra -> {
|
||||||
|
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_card_slot))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
R.id.bt_insert_time -> {
|
||||||
|
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_receive_time))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
R.id.bt_insert_device_name -> {
|
||||||
|
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_device_name))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
R.id.btn_test -> {
|
||||||
|
mCountDownHelper?.start()
|
||||||
|
Thread {
|
||||||
|
try {
|
||||||
|
val settingVo = checkSetting()
|
||||||
|
Log.d(TAG, settingVo.toString())
|
||||||
|
val msgInfo = MsgInfo("sms", getString(R.string.test_phone_num), getString(R.string.test_sender_sms), Date(), getString(R.string.test_sim_info))
|
||||||
|
FeishuAppUtils.sendMsg(settingVo, msgInfo)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare()
|
||||||
|
XToastUtils.error(e.message.toString())
|
||||||
|
Looper.loop()
|
||||||
|
}
|
||||||
|
LiveEventBus.get(KEY_SENDER_TEST, String::class.java).post("finish")
|
||||||
|
}.start()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
R.id.btn_del -> {
|
||||||
|
if (senderId <= 0 || isClone) {
|
||||||
|
popToBack()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialDialog.Builder(requireContext())
|
||||||
|
.title(R.string.delete_sender_title)
|
||||||
|
.content(R.string.delete_sender_tips)
|
||||||
|
.positiveText(R.string.lab_yes)
|
||||||
|
.negativeText(R.string.lab_no)
|
||||||
|
.onPositive { _: MaterialDialog?, _: DialogAction? ->
|
||||||
|
viewModel.delete(senderId)
|
||||||
|
XToastUtils.success(R.string.delete_sender_toast)
|
||||||
|
popToBack()
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
R.id.btn_save -> {
|
||||||
|
val name = binding!!.etName.text.toString().trim()
|
||||||
|
if (TextUtils.isEmpty(name)) {
|
||||||
|
throw Exception(getString(R.string.invalid_name))
|
||||||
|
}
|
||||||
|
|
||||||
|
val status = if (binding!!.sbEnable.isChecked) 1 else 0
|
||||||
|
val settingVo = checkSetting()
|
||||||
|
if (isClone) senderId = 0
|
||||||
|
val senderNew = Sender(senderId, senderType, name, Gson().toJson(settingVo), status)
|
||||||
|
Log.d(TAG, senderNew.toString())
|
||||||
|
|
||||||
|
viewModel.insertOrUpdate(senderNew)
|
||||||
|
XToastUtils.success(R.string.tipSaveSuccess)
|
||||||
|
popToBack()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
XToastUtils.error(e.message.toString())
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkSetting(): FeishuAppSetting {
|
||||||
|
val appId = binding!!.etAppId.text.toString().trim()
|
||||||
|
val appSecret = binding!!.etAppSecret.text.toString().trim()
|
||||||
|
val receiveId = binding!!.etUserId.text.toString().trim()
|
||||||
|
if (TextUtils.isEmpty(appId) || TextUtils.isEmpty(appSecret) || TextUtils.isEmpty(receiveId)) {
|
||||||
|
throw Exception(getString(R.string.invalid_feishu_app_parameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
val msgType = if (binding!!.rgMsgType.checkedRadioButtonId == R.id.rb_msg_type_interactive) "interactive" else "text"
|
||||||
|
val title = binding!!.etTitleTemplate.text.toString().trim()
|
||||||
|
|
||||||
|
return FeishuAppSetting(appId, appSecret, receiveId, msgType, title)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
if (mCountDownHelper != null) mCountDownHelper!!.recycle()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ 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 FeishuFragment : BaseFragment<FragmentSendersFeishuBinding?>(), View.OnClickListener {
|
class FeishuFragment : BaseFragment<FragmentSendersFeishuBinding?>(), View.OnClickListener {
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,7 @@ const val TYPE_FEISHU = 9
|
||||||
const val TYPE_PUSHPLUS = 10
|
const val TYPE_PUSHPLUS = 10
|
||||||
const val TYPE_GOTIFY = 11
|
const val TYPE_GOTIFY = 11
|
||||||
const val TYPE_DINGTALK_INNER_ROBOT = 12
|
const val TYPE_DINGTALK_INNER_ROBOT = 12
|
||||||
|
const val TYPE_FEISHU_APP = 13
|
||||||
var SENDER_FRAGMENT_LIST = listOf(
|
var SENDER_FRAGMENT_LIST = listOf(
|
||||||
PageInfo(getString(R.string.dingtalk_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkGroupRobotFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_dingtalk),
|
PageInfo(getString(R.string.dingtalk_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkGroupRobotFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_dingtalk),
|
||||||
PageInfo(getString(R.string.email), "com.idormy.sms.forwarder.fragment.senders.EmailFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_email),
|
PageInfo(getString(R.string.email), "com.idormy.sms.forwarder.fragment.senders.EmailFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_email),
|
||||||
|
@ -175,6 +176,7 @@ var SENDER_FRAGMENT_LIST = listOf(
|
||||||
PageInfo(getString(R.string.pushplus), "com.idormy.sms.forwarder.fragment.senders.PushplusFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_pushplus),
|
PageInfo(getString(R.string.pushplus), "com.idormy.sms.forwarder.fragment.senders.PushplusFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_pushplus),
|
||||||
PageInfo(getString(R.string.gotify), "com.idormy.sms.forwarder.fragment.senders.GotifyFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_gotify),
|
PageInfo(getString(R.string.gotify), "com.idormy.sms.forwarder.fragment.senders.GotifyFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_gotify),
|
||||||
PageInfo(getString(R.string.dingtalk_inner_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkInnerRobotFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_dingtalk_inner),
|
PageInfo(getString(R.string.dingtalk_inner_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkInnerRobotFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_dingtalk_inner),
|
||||||
|
PageInfo(getString(R.string.feishu_app), "com.idormy.sms.forwarder.fragment.senders.FeishuAppFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_feishu_app),
|
||||||
)
|
)
|
||||||
|
|
||||||
//前台服务
|
//前台服务
|
||||||
|
|
|
@ -123,6 +123,10 @@ object SendUtils {
|
||||||
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkInnerRobotSetting::class.java)
|
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkInnerRobotSetting::class.java)
|
||||||
DingtalkInnerRobotUtils.sendMsg(settingVo, msgInfo, rule, logId)
|
DingtalkInnerRobotUtils.sendMsg(settingVo, msgInfo, rule, logId)
|
||||||
}
|
}
|
||||||
|
TYPE_FEISHU_APP -> {
|
||||||
|
val settingVo = Gson().fromJson(sender.jsonSetting, FeishuAppSetting::class.java)
|
||||||
|
FeishuAppUtils.sendMsg(settingVo, msgInfo, rule, logId)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
updateLogs(logId, 0, "未知发送通道")
|
updateLogs(logId, 0, "未知发送通道")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
package com.idormy.sms.forwarder.utils.sender
|
||||||
|
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.util.Log
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.idormy.sms.forwarder.R
|
||||||
|
import com.idormy.sms.forwarder.database.entity.Rule
|
||||||
|
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||||
|
import com.idormy.sms.forwarder.entity.result.FeishuAppResult
|
||||||
|
import com.idormy.sms.forwarder.entity.setting.FeishuAppSetting
|
||||||
|
import com.idormy.sms.forwarder.utils.MMKVUtils
|
||||||
|
import com.idormy.sms.forwarder.utils.SendUtils
|
||||||
|
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||||
|
import com.xuexiang.xhttp2.XHttp
|
||||||
|
import com.xuexiang.xhttp2.cache.model.CacheMode
|
||||||
|
import com.xuexiang.xhttp2.callback.SimpleCallBack
|
||||||
|
import com.xuexiang.xhttp2.exception.ApiException
|
||||||
|
import com.xuexiang.xui.utils.ResUtils.getString
|
||||||
|
|
||||||
|
//飞书企业应用
|
||||||
|
@Suppress("PrivatePropertyName", "UNUSED_PARAMETER")
|
||||||
|
class FeishuAppUtils private constructor() {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val TAG: String = FeishuAppUtils::class.java.simpleName
|
||||||
|
|
||||||
|
fun sendMsg(
|
||||||
|
setting: FeishuAppSetting,
|
||||||
|
msgInfo: MsgInfo,
|
||||||
|
rule: Rule?,
|
||||||
|
logId: Long?,
|
||||||
|
) {
|
||||||
|
|
||||||
|
val accessToken: String? = MMKVUtils.getString("feishu_access_token_" + setting.appId, "")
|
||||||
|
val expiresIn: Long = MMKVUtils.getLong("feishu_expires_in_" + setting.appId, 0L)
|
||||||
|
if (!TextUtils.isEmpty(accessToken) && expiresIn > System.currentTimeMillis()) {
|
||||||
|
return sendTextMsg(setting, msgInfo, rule, logId)
|
||||||
|
}
|
||||||
|
|
||||||
|
val requestUrl = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
|
||||||
|
Log.d(TAG, "requestUrl:$requestUrl")
|
||||||
|
|
||||||
|
val msgMap: MutableMap<String, Any> = mutableMapOf()
|
||||||
|
msgMap["app_id"] = setting.appId
|
||||||
|
msgMap["app_secret"] = setting.appSecret
|
||||||
|
val requestMsg: String = Gson().toJson(msgMap)
|
||||||
|
Log.i(TAG, "requestMsg:$requestMsg")
|
||||||
|
|
||||||
|
XHttp.post(requestUrl)
|
||||||
|
.upJson(requestMsg)
|
||||||
|
.keepJson(true)
|
||||||
|
.ignoreHttpsCert()
|
||||||
|
.timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s
|
||||||
|
.cacheMode(CacheMode.NO_CACHE)
|
||||||
|
.timeStamp(true)
|
||||||
|
.execute(object : SimpleCallBack<String>() {
|
||||||
|
|
||||||
|
override fun onError(e: ApiException) {
|
||||||
|
Log.e(TAG, e.detailMessage)
|
||||||
|
SendUtils.updateLogs(logId, 0, e.displayMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(response: String) {
|
||||||
|
Log.i(TAG, response)
|
||||||
|
|
||||||
|
val resp = Gson().fromJson(response, FeishuAppResult::class.java)
|
||||||
|
if (!TextUtils.isEmpty(resp.tenant_access_token)) {
|
||||||
|
MMKVUtils.put("feishu_access_token_" + setting.appId, resp.tenant_access_token)
|
||||||
|
MMKVUtils.put("feishu_expires_in_" + setting.appId, System.currentTimeMillis() + ((resp.expire ?: 7010) - 120) * 1000L) //提前2分钟过期
|
||||||
|
sendTextMsg(setting, msgInfo, rule, logId)
|
||||||
|
} else {
|
||||||
|
SendUtils.updateLogs(logId, 0, String.format(getString(R.string.request_failed_tips), response))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送文本消息
|
||||||
|
private fun sendTextMsg(
|
||||||
|
setting: FeishuAppSetting,
|
||||||
|
msgInfo: MsgInfo,
|
||||||
|
rule: Rule?,
|
||||||
|
logId: Long?,
|
||||||
|
) {
|
||||||
|
val requestUrl = "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=user_id"
|
||||||
|
Log.d(TAG, "requestUrl:$requestUrl")
|
||||||
|
|
||||||
|
val content: String = if (rule != null) {
|
||||||
|
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)
|
||||||
|
} else {
|
||||||
|
msgInfo.getContentForSend(SettingUtils.smsTemplate.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
val msgContent = if ("interactive" == setting.msgType) {
|
||||||
|
val title = if (rule != null) {
|
||||||
|
msgInfo.getTitleForSend(setting.titleTemplate, rule.regexReplace)
|
||||||
|
} else {
|
||||||
|
msgInfo.getTitleForSend(setting.titleTemplate)
|
||||||
|
}
|
||||||
|
"{\"elements\":[{\"tag\":\"markdown\",\"content\":\"**[{{MSG_TITLE}}]({{MSG_URL}})**\\n --------------\\n{{MSG_CONTENT}}\"}]}".trimIndent().replace("{{MSG_TITLE}}", jsonInnerStr(title))
|
||||||
|
.replace("{{MSG_URL}}", jsonInnerStr("https://github.com/pppscn/SmsForwarder"))
|
||||||
|
.replace("{{MSG_CONTENT}}", jsonInnerStr(content))
|
||||||
|
} else {
|
||||||
|
"{\"text\":\"{{MSG_CONTENT}}\"}".trimIndent().replace("{{MSG_CONTENT}}", jsonInnerStr(content))
|
||||||
|
}
|
||||||
|
|
||||||
|
val textMsgMap: MutableMap<String, Any> = mutableMapOf()
|
||||||
|
textMsgMap["receive_id"] = setting.receiveId
|
||||||
|
textMsgMap["msg_type"] = setting.msgType
|
||||||
|
textMsgMap["content"] = msgContent
|
||||||
|
|
||||||
|
val requestMsg: String = Gson().toJson(textMsgMap)
|
||||||
|
Log.i(TAG, "requestMsg:$requestMsg")
|
||||||
|
|
||||||
|
XHttp.post(requestUrl)
|
||||||
|
.upJson(requestMsg)
|
||||||
|
.headers("Authorization", "Bearer " + MMKVUtils.getString("feishu_access_token_" + setting.appId, ""))
|
||||||
|
.keepJson(true)
|
||||||
|
//.ignoreHttpsCert()
|
||||||
|
.timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s
|
||||||
|
.cacheMode(CacheMode.NO_CACHE)
|
||||||
|
.retryCount(SettingUtils.requestRetryTimes) //超时重试的次数
|
||||||
|
.retryDelay(SettingUtils.requestDelayTime) //超时重试的延迟时间
|
||||||
|
.retryIncreaseDelay(SettingUtils.requestDelayTime) //超时重试叠加延时
|
||||||
|
.timeStamp(true)
|
||||||
|
.execute(object : SimpleCallBack<String>() {
|
||||||
|
|
||||||
|
override fun onError(e: ApiException) {
|
||||||
|
Log.e(TAG, e.detailMessage)
|
||||||
|
SendUtils.updateLogs(logId, 0, e.displayMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(response: String) {
|
||||||
|
Log.i(TAG, response)
|
||||||
|
//Log.d(TAG, "tlsVersion=" + response.handshake().tlsVersion())
|
||||||
|
//Log.d(TAG, "cipherSuite=" + response.handshake().cipherSuite().toString())
|
||||||
|
|
||||||
|
val resp = Gson().fromJson(response, FeishuAppResult::class.java)
|
||||||
|
if (resp.code == 0L) {
|
||||||
|
SendUtils.updateLogs(logId, 2, response)
|
||||||
|
} else {
|
||||||
|
SendUtils.updateLogs(logId, 0, response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendMsg(setting: FeishuAppSetting, msgInfo: MsgInfo) {
|
||||||
|
sendMsg(setting, msgInfo, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun jsonInnerStr(string: String?): String {
|
||||||
|
if (string == null) return "null"
|
||||||
|
|
||||||
|
val jsonStr: String = Gson().toJson(string)
|
||||||
|
return if (jsonStr.length >= 2) jsonStr.substring(1, jsonStr.length - 1) else jsonStr
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,268 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/xui_config_color_background"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:overScrollMode="never">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/senderBarStyleWithSwitch"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/sender_name_status"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:met_clearButton="true" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
||||||
|
android:id="@+id/sb_enable"
|
||||||
|
style="@style/SwitchButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/senderBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="75dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:text="@string/app_id"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_app_id"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:met_passWordButton="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/senderBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="75dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:text="@string/app_secret"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_app_secret"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:met_passWordButton="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/senderBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="75dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:text="@string/user_id"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_user_id"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:met_passWordButton="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/senderBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="75dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:text="@string/feishu_msg_type"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/rg_msg_type"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/rb_msg_type_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/feishu_msg_type_text" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/rb_msg_type_interactive"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/feishu_msg_type_interactive" />
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_custom_template"
|
||||||
|
style="@style/senderBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/title_template"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:text="@string/custom_template_tips"
|
||||||
|
android:textSize="10sp"
|
||||||
|
tools:ignore="SmallSp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_title_template"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:met_clearButton="true" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
|
||||||
|
android:id="@+id/bt_insert_sender"
|
||||||
|
style="@style/insertButtonStyle"
|
||||||
|
android:text="@string/insert_sender" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
|
||||||
|
android:id="@+id/bt_insert_extra"
|
||||||
|
style="@style/insertButtonStyle"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:text="@string/insert_extra" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
|
||||||
|
android:id="@+id/bt_insert_time"
|
||||||
|
style="@style/insertButtonStyle"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:text="@string/insert_time" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
|
||||||
|
android:id="@+id/bt_insert_device_name"
|
||||||
|
style="@style/insertButtonStyle"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:text="@string/insert_device_name" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
<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>
|
|
@ -485,6 +485,7 @@
|
||||||
<string name="telegram">Telegram Bot</string>
|
<string name="telegram">Telegram Bot</string>
|
||||||
<string name="sms_menu">SMS</string>
|
<string name="sms_menu">SMS</string>
|
||||||
<string name="feishu">FeiShu Bot</string>
|
<string name="feishu">FeiShu Bot</string>
|
||||||
|
<string name="feishu_app">FeiShu App</string>
|
||||||
<string name="pushplus">PushPlus</string>
|
<string name="pushplus">PushPlus</string>
|
||||||
<string name="gotify">Gotify</string>
|
<string name="gotify">Gotify</string>
|
||||||
<string name="_0">0</string>
|
<string name="_0">0</string>
|
||||||
|
@ -892,20 +893,24 @@
|
||||||
<string name="sampleMarkdown">Markdown</string>
|
<string name="sampleMarkdown">Markdown</string>
|
||||||
<string name="ip_hint">IP address/broadcast address, eg. 192.168.1.255</string>
|
<string name="ip_hint">IP address/broadcast address, eg. 192.168.1.255</string>
|
||||||
<string name="ip_error">Malformed IP address, eg. 192.168.168.168</string>
|
<string name="ip_error">Malformed IP address, eg. 192.168.168.168</string>
|
||||||
<string name="ip_regex">^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$</string>
|
<string name="ip_regex" tools:ignore="TypographyDashes">^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$</string>
|
||||||
<string name="mac_hint">Network card mac, eg. AA:BB:CC:DD:EE:FF</string>
|
<string name="mac_hint">Network card mac, eg. AA:BB:CC:DD:EE:FF</string>
|
||||||
<string name="mac_error">The network card mac format is incorrect, eg. AA:BB:CC:DD:EE:FF</string>
|
<string name="mac_error">The network card mac format is incorrect, eg. AA:BB:CC:DD:EE:FF</string>
|
||||||
<string name="mac_regex">^((([a-fA-F0-9]{2}:){5})|(([a-fA-F0-9]{2}-){5}))[a-fA-F0-9]{2}$</string>
|
<string name="mac_regex" tools:ignore="TypographyDashes">^((([a-fA-F0-9]{2}:){5})|(([a-fA-F0-9]{2}-){5}))[a-fA-F0-9]{2}$</string>
|
||||||
<string name="ip">IP</string>
|
<string name="ip">IP</string>
|
||||||
<string name="mac">MAC</string>
|
<string name="mac">MAC</string>
|
||||||
<string name="no_wol_history">There is no history record, WOL will be added automatically after successful sending</string>
|
<string name="no_wol_history">There is no history record, WOL will be added automatically after successful sending</string>
|
||||||
<string name="wol_port_hint">WOL is generally sent over port 7 or port 9</string>
|
<string name="wol_port_hint">WOL is generally sent over port 7 or port 9</string>
|
||||||
<string name="wol_port_error">Port number value range: 1~65535</string>
|
<string name="wol_port_error">Port number value range: 1~65535</string>
|
||||||
<string name="wol_port_regex">^([0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$</string>
|
<string name="wol_port_regex" tools:ignore="TypographyDashes">^([0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$</string>
|
||||||
<string name="select_directory">Select Dir</string>
|
<string name="select_directory">Select Dir</string>
|
||||||
<string name="web_client">Web Client</string>
|
<string name="web_client">Web Client</string>
|
||||||
<string name="restarting_httpserver">Restarting HttpServer</string>
|
<string name="restarting_httpserver">Restarting HttpServer</string>
|
||||||
<string name="download_first">Download and unzip to:\n%s</string>
|
<string name="download_first">Download and unzip to:\n%s</string>
|
||||||
<string name="root_directory">Root Directory:\n%s</string>
|
<string name="root_directory">Root Directory:\n%s</string>
|
||||||
<string name="select_web_client_directory">Select WebClient Directory</string>
|
<string name="select_web_client_directory">Select WebClient Directory</string>
|
||||||
|
<string name="invalid_feishu_app_parameter">AppId/AppSecret/UserId cannot be empty</string>
|
||||||
|
<string name="app_id">App ID</string>
|
||||||
|
<string name="app_secret">App Secret</string>
|
||||||
|
<string name="user_id">User ID</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -266,7 +266,7 @@
|
||||||
<string name="setserverchantitle">设置Server酱·Turbo版</string>
|
<string name="setserverchantitle">设置Server酱·Turbo版</string>
|
||||||
<string name="settelegramtitle">设置Telegram机器人</string>
|
<string name="settelegramtitle">设置Telegram机器人</string>
|
||||||
<string name="setsmstitle">设置SMS</string>
|
<string name="setsmstitle">设置SMS</string>
|
||||||
<string name="setfeishutitle">设置飞书机器人</string>
|
<string name="setfeishutitle">设置飞书群机器人</string>
|
||||||
<string name="setpushplustitle">设置PushPlus</string>
|
<string name="setpushplustitle">设置PushPlus</string>
|
||||||
<string name="setgotifytitle">设置Gotify</string>
|
<string name="setgotifytitle">设置Gotify</string>
|
||||||
<string name="test_phone_num">19999999999</string>
|
<string name="test_phone_num">19999999999</string>
|
||||||
|
@ -485,7 +485,8 @@
|
||||||
<string name="server_chan">Server酱·Turbo版</string>
|
<string name="server_chan">Server酱·Turbo版</string>
|
||||||
<string name="telegram">Telegram机器人</string>
|
<string name="telegram">Telegram机器人</string>
|
||||||
<string name="sms_menu">手机短信</string>
|
<string name="sms_menu">手机短信</string>
|
||||||
<string name="feishu">飞书机器人</string>
|
<string name="feishu">飞书群机器人</string>
|
||||||
|
<string name="feishu_app">飞书企业应用</string>
|
||||||
<string name="pushplus">PushPlus</string>
|
<string name="pushplus">PushPlus</string>
|
||||||
<string name="gotify">Gotify</string>
|
<string name="gotify">Gotify</string>
|
||||||
<string name="_0">0</string>
|
<string name="_0">0</string>
|
||||||
|
@ -771,7 +772,7 @@
|
||||||
<string name="http_server_stopped">HttpServer已停止</string>
|
<string name="http_server_stopped">HttpServer已停止</string>
|
||||||
<string name="server_settings">服务端设置</string>
|
<string name="server_settings">服务端设置</string>
|
||||||
<string name="server_settings_tips">建议启用签名设置、点击“随机”自动生成并复制到剪贴板</string>
|
<string name="server_settings_tips">建议启用签名设置、点击“随机”自动生成并复制到剪贴板</string>
|
||||||
<string name="copy">复制</string>
|
<string name="copy" tools:ignore="PrivateResource">复制</string>
|
||||||
<string name="random">随机生成</string>
|
<string name="random">随机生成</string>
|
||||||
<string name="sign_key">签名密钥</string>
|
<string name="sign_key">签名密钥</string>
|
||||||
<string name="sign_key_tips">已生成密钥,并复制到剪贴板</string>
|
<string name="sign_key_tips">已生成密钥,并复制到剪贴板</string>
|
||||||
|
@ -893,20 +894,24 @@
|
||||||
<string name="sampleMarkdown">Markdown类型</string>
|
<string name="sampleMarkdown">Markdown类型</string>
|
||||||
<string name="ip_hint">可选,主机IP/广播地址,例如:192.168.1.255</string>
|
<string name="ip_hint">可选,主机IP/广播地址,例如:192.168.1.255</string>
|
||||||
<string name="ip_error">IP地址格式错误,例如:192.168.168.168</string>
|
<string name="ip_error">IP地址格式错误,例如:192.168.168.168</string>
|
||||||
<string name="ip_regex">^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$</string>
|
<string name="ip_regex" tools:ignore="TypographyDashes">^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$</string>
|
||||||
<string name="mac_hint">必填,网卡mac,例如:AA:BB:CC:DD:EE:FF</string>
|
<string name="mac_hint">必填,网卡mac,例如:AA:BB:CC:DD:EE:FF</string>
|
||||||
<string name="mac_error">网卡mac格式错误,例如:AA:BB:CC:DD:EE:FF</string>
|
<string name="mac_error">网卡mac格式错误,例如:AA:BB:CC:DD:EE:FF</string>
|
||||||
<string name="mac_regex">^((([a-fA-F0-9]{2}:){5})|(([a-fA-F0-9]{2}-){5}))[a-fA-F0-9]{2}$</string>
|
<string name="mac_regex" tools:ignore="TypographyDashes">^((([a-fA-F0-9]{2}:){5})|(([a-fA-F0-9]{2}-){5}))[a-fA-F0-9]{2}$</string>
|
||||||
<string name="ip">主机IP/广播地址</string>
|
<string name="ip">主机IP/广播地址</string>
|
||||||
<string name="mac">网卡MAC</string>
|
<string name="mac">网卡MAC</string>
|
||||||
<string name="no_wol_history">暂无历史记录,WOL发送成功后自动加入</string>
|
<string name="no_wol_history">暂无历史记录,WOL发送成功后自动加入</string>
|
||||||
<string name="wol_port_hint">可选,WOL一般透过端口7或端口9进行发送</string>
|
<string name="wol_port_hint">可选,WOL一般透过端口7或端口9进行发送</string>
|
||||||
<string name="wol_port_error">端口号取值范围:1~65535</string>
|
<string name="wol_port_error">端口号取值范围:1~65535</string>
|
||||||
<string name="wol_port_regex">^([0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$</string>
|
<string name="wol_port_regex" tools:ignore="TypographyDashes">^([0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$</string>
|
||||||
<string name="select_directory">选择目录</string>
|
<string name="select_directory">选择目录</string>
|
||||||
<string name="web_client">Web客户端</string>
|
<string name="web_client">Web客户端</string>
|
||||||
<string name="restarting_httpserver">正在重启HttpServer</string>
|
<string name="restarting_httpserver">正在重启HttpServer</string>
|
||||||
<string name="download_first">请先下载Web客户端并解压到:\n%s</string>
|
<string name="download_first">请先下载Web客户端并解压到:\n%s</string>
|
||||||
<string name="root_directory">根目录:\n%s</string>
|
<string name="root_directory">根目录:\n%s</string>
|
||||||
<string name="select_web_client_directory">选择Web客户端目录</string>
|
<string name="select_web_client_directory">选择Web客户端目录</string>
|
||||||
|
<string name="invalid_feishu_app_parameter">AppId/AppSecret/UserId都不能为空</string>
|
||||||
|
<string name="app_id">App ID</string>
|
||||||
|
<string name="app_secret">App Secret</string>
|
||||||
|
<string name="user_id">User ID</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue