mirror of
https://github.com/pppscn/SmsForwarder
synced 2024-11-04 06:00:11 +00:00
新增:钉钉企业内机器人
发送通道
This commit is contained in:
parent
56d83ed0aa
commit
a7746f3b8d
@ -10,7 +10,7 @@
|
||||
|
||||
短信转发器——不仅只转发短信,备用机必备神器!
|
||||
|
||||
监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。
|
||||
监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉群自定义机器人、钉钉企业内机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。
|
||||
|
||||
包括主动控制服务端与客户端,让你轻松远程发短信、查短信、查通话、查话簿、查电量等。(V3.0 新增)
|
||||
|
||||
|
@ -23,7 +23,7 @@ data class Sender(
|
||||
companion object {
|
||||
|
||||
fun getImageId(type: Int): Int = when (type) {
|
||||
TYPE_DINGDING -> R.drawable.icon_dingtalk
|
||||
TYPE_DINGTALK_GROUP_ROBOT -> R.drawable.icon_dingtalk
|
||||
TYPE_EMAIL -> R.drawable.icon_email
|
||||
TYPE_BARK -> R.drawable.icon_bark
|
||||
TYPE_WEBHOOK -> R.drawable.icon_webhook
|
||||
@ -35,6 +35,7 @@ data class Sender(
|
||||
TYPE_PUSHPLUS -> R.drawable.icon_pushplus
|
||||
TYPE_GOTIFY -> R.drawable.icon_gotify
|
||||
TYPE_SMS -> R.drawable.icon_sms
|
||||
TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner
|
||||
else -> R.drawable.icon_sms
|
||||
}
|
||||
|
||||
@ -42,7 +43,7 @@ data class Sender(
|
||||
|
||||
val imageId: Int
|
||||
get() = when (type) {
|
||||
TYPE_DINGDING -> R.drawable.icon_dingtalk
|
||||
TYPE_DINGTALK_GROUP_ROBOT -> R.drawable.icon_dingtalk
|
||||
TYPE_EMAIL -> R.drawable.icon_email
|
||||
TYPE_BARK -> R.drawable.icon_bark
|
||||
TYPE_WEBHOOK -> R.drawable.icon_webhook
|
||||
@ -54,6 +55,7 @@ data class Sender(
|
||||
TYPE_PUSHPLUS -> R.drawable.icon_pushplus
|
||||
TYPE_GOTIFY -> R.drawable.icon_gotify
|
||||
TYPE_SMS -> R.drawable.icon_sms
|
||||
TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner
|
||||
else -> R.drawable.icon_sms
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.idormy.sms.forwarder.entity.result
|
||||
|
||||
data class DingtalkInnerRobotResult(
|
||||
//获取access_token返回
|
||||
var accessToken: String?,
|
||||
var expireIn: Long?,
|
||||
//消息id
|
||||
var processQueryKey: String?,
|
||||
//无效的用户userid列表
|
||||
//var invalidStaffIdList: String[],
|
||||
//被限流的userid列表
|
||||
//var flowControlledStaffIdList: String[],
|
||||
)
|
@ -2,7 +2,7 @@ package com.idormy.sms.forwarder.entity.setting
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class DingtalkSetting(
|
||||
data class DingtalkGroupRobotSetting(
|
||||
var token: String = "",
|
||||
var secret: String? = "",
|
||||
var atAll: Boolean? = false,
|
@ -0,0 +1,37 @@
|
||||
package com.idormy.sms.forwarder.entity.setting
|
||||
|
||||
import com.idormy.sms.forwarder.R
|
||||
import java.io.Serializable
|
||||
import java.net.Proxy
|
||||
|
||||
data class DingtalkInnerRobotSetting(
|
||||
val agentID: String = "",
|
||||
val appKey: String = "",
|
||||
val appSecret: String = "",
|
||||
val userIds: String = "",
|
||||
val msgKey: String = "sampleText",
|
||||
val titleTemplate: String? = "",
|
||||
val proxyType: Proxy.Type = Proxy.Type.DIRECT,
|
||||
val proxyHost: String? = "",
|
||||
val proxyPort: String? = "",
|
||||
val proxyAuthenticator: Boolean? = false,
|
||||
val proxyUsername: String? = "",
|
||||
val proxyPassword: String? = "",
|
||||
) : Serializable {
|
||||
|
||||
fun getProxyTypeCheckId(): Int {
|
||||
return when (proxyType) {
|
||||
Proxy.Type.HTTP -> R.id.rb_proxyHttp
|
||||
Proxy.Type.SOCKS -> R.id.rb_proxySocks
|
||||
else -> R.id.rb_proxyNone
|
||||
}
|
||||
}
|
||||
|
||||
fun getMsgTypeCheckId(): Int {
|
||||
return if (msgKey == "sampleMarkdown") {
|
||||
R.id.rb_msg_type_markdown
|
||||
} else {
|
||||
R.id.rb_msg_type_text
|
||||
}
|
||||
}
|
||||
}
|
@ -95,7 +95,7 @@ class SendersFragment : BaseFragment<FragmentSendersBinding?>(), SenderPagingAda
|
||||
R.id.iv_copy -> {
|
||||
PageOption.to(
|
||||
when (item.type) {
|
||||
TYPE_DINGDING -> DingtalkFragment::class.java
|
||||
TYPE_DINGTALK_GROUP_ROBOT -> DingtalkGroupRobotFragment::class.java
|
||||
TYPE_EMAIL -> EmailFragment::class.java
|
||||
TYPE_BARK -> BarkFragment::class.java
|
||||
TYPE_WEBHOOK -> WebhookFragment::class.java
|
||||
@ -107,7 +107,8 @@ class SendersFragment : BaseFragment<FragmentSendersBinding?>(), SenderPagingAda
|
||||
TYPE_FEISHU -> FeishuFragment::class.java
|
||||
TYPE_PUSHPLUS -> PushplusFragment::class.java
|
||||
TYPE_GOTIFY -> GotifyFragment::class.java
|
||||
else -> DingtalkFragment::class.java
|
||||
TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java
|
||||
else -> DingtalkGroupRobotFragment::class.java
|
||||
}
|
||||
).setNewActivity(true)
|
||||
.putLong(KEY_SENDER_ID, item.id)
|
||||
@ -118,7 +119,7 @@ class SendersFragment : BaseFragment<FragmentSendersBinding?>(), SenderPagingAda
|
||||
R.id.iv_edit -> {
|
||||
PageOption.to(
|
||||
when (item.type) {
|
||||
TYPE_DINGDING -> DingtalkFragment::class.java
|
||||
TYPE_DINGTALK_GROUP_ROBOT -> DingtalkGroupRobotFragment::class.java
|
||||
TYPE_EMAIL -> EmailFragment::class.java
|
||||
TYPE_BARK -> BarkFragment::class.java
|
||||
TYPE_WEBHOOK -> WebhookFragment::class.java
|
||||
@ -130,7 +131,8 @@ class SendersFragment : BaseFragment<FragmentSendersBinding?>(), SenderPagingAda
|
||||
TYPE_FEISHU -> FeishuFragment::class.java
|
||||
TYPE_PUSHPLUS -> PushplusFragment::class.java
|
||||
TYPE_GOTIFY -> GotifyFragment::class.java
|
||||
else -> DingtalkFragment::class.java
|
||||
TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java
|
||||
else -> DingtalkGroupRobotFragment::class.java
|
||||
}
|
||||
).setNewActivity(true)
|
||||
.putLong(KEY_SENDER_ID, item.id)
|
||||
|
@ -15,11 +15,11 @@ 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.FragmentSendersDingtalkBinding
|
||||
import com.idormy.sms.forwarder.databinding.FragmentSendersDingtalkGroupRobotBinding
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
import com.idormy.sms.forwarder.entity.setting.DingtalkSetting
|
||||
import com.idormy.sms.forwarder.entity.setting.DingtalkGroupRobotSetting
|
||||
import com.idormy.sms.forwarder.utils.*
|
||||
import com.idormy.sms.forwarder.utils.sender.DingtalkUtils
|
||||
import com.idormy.sms.forwarder.utils.sender.DingtalkGroupRobotUtils
|
||||
import com.xuexiang.xaop.annotation.SingleClick
|
||||
import com.xuexiang.xpage.annotation.Page
|
||||
import com.xuexiang.xrouter.annotation.AutoWired
|
||||
@ -34,11 +34,11 @@ import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.*
|
||||
|
||||
@Page(name = "钉钉机器人")
|
||||
@Page(name = "钉钉群机器人")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class DingtalkFragment : BaseFragment<FragmentSendersDingtalkBinding?>(), View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
||||
class DingtalkGroupRobotFragment : BaseFragment<FragmentSendersDingtalkGroupRobotBinding?>(), View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
||||
|
||||
private val TAG: String = DingtalkFragment::class.java.simpleName
|
||||
private val TAG: String = DingtalkGroupRobotFragment::class.java.simpleName
|
||||
var titleBar: TitleBar? = null
|
||||
private val viewModel by viewModels<SenderViewModel> { BaseViewModelFactory(context) }
|
||||
private var mCountDownHelper: CountDownButtonHelper? = null
|
||||
@ -62,8 +62,8 @@ class DingtalkFragment : BaseFragment<FragmentSendersDingtalkBinding?>(), View.O
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentSendersDingtalkBinding {
|
||||
return FragmentSendersDingtalkBinding.inflate(inflater, container, false)
|
||||
): FragmentSendersDingtalkGroupRobotBinding {
|
||||
return FragmentSendersDingtalkGroupRobotBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
@ -117,7 +117,7 @@ class DingtalkFragment : BaseFragment<FragmentSendersDingtalkBinding?>(), View.O
|
||||
}
|
||||
binding!!.etName.setText(sender.name)
|
||||
binding!!.sbEnable.isChecked = sender.status == 1
|
||||
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkSetting::class.java)
|
||||
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkGroupRobotSetting::class.java)
|
||||
Log.d(TAG, settingVo.toString())
|
||||
if (settingVo != null) {
|
||||
binding!!.etToken.setText(settingVo.token)
|
||||
@ -164,7 +164,7 @@ class DingtalkFragment : BaseFragment<FragmentSendersDingtalkBinding?>(), View.O
|
||||
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))
|
||||
DingtalkUtils.sendMsg(settingVo, msgInfo)
|
||||
DingtalkGroupRobotUtils.sendMsg(settingVo, msgInfo)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
if (Looper.myLooper() == null) Looper.prepare()
|
||||
@ -217,7 +217,7 @@ class DingtalkFragment : BaseFragment<FragmentSendersDingtalkBinding?>(), View.O
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkSetting(): DingtalkSetting {
|
||||
private fun checkSetting(): DingtalkGroupRobotSetting {
|
||||
val token = binding!!.etToken.text.toString().trim()
|
||||
if (CommonUtils.checkUrl(token, true)) {
|
||||
throw Exception(getString(R.string.invalid_token))
|
||||
@ -230,7 +230,7 @@ class DingtalkFragment : BaseFragment<FragmentSendersDingtalkBinding?>(), View.O
|
||||
throw Exception(getString(R.string.invalid_at_mobiles))
|
||||
}*/
|
||||
|
||||
return DingtalkSetting(token, secret, atAll, atMobiles)
|
||||
return DingtalkGroupRobotSetting(token, secret, atAll, atMobiles)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
@ -0,0 +1,299 @@
|
||||
package com.idormy.sms.forwarder.fragment.senders
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
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.CompoundButton
|
||||
import android.widget.EditText
|
||||
import android.widget.RadioGroup
|
||||
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.FragmentSendersDingtalkInnerRobotBinding
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
import com.idormy.sms.forwarder.entity.setting.DingtalkInnerRobotSetting
|
||||
import com.idormy.sms.forwarder.utils.*
|
||||
import com.idormy.sms.forwarder.utils.sender.DingtalkInnerRobotUtils
|
||||
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.net.Proxy
|
||||
import java.util.*
|
||||
|
||||
@Page(name = "钉钉企业机器人")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class DingtalkInnerRobotFragment : BaseFragment<FragmentSendersDingtalkInnerRobotBinding?>(), View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
||||
|
||||
private val TAG: String = DingtalkInnerRobotFragment::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,
|
||||
): FragmentSendersDingtalkInnerRobotBinding {
|
||||
return FragmentSendersDingtalkInnerRobotBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.dingtalk_inner_robot)
|
||||
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, DingtalkInnerRobotSetting::class.java)
|
||||
Log.d(TAG, settingVo.toString())
|
||||
if (settingVo != null) {
|
||||
binding!!.etAgentID.setText(settingVo.agentID)
|
||||
binding!!.etAppKey.setText(settingVo.appKey)
|
||||
binding!!.etAppSecret.setText(settingVo.appSecret)
|
||||
binding!!.etUserIds.setText(settingVo.userIds)
|
||||
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
|
||||
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
|
||||
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
|
||||
binding!!.etProxyHost.setText(settingVo.proxyHost)
|
||||
binding!!.etProxyPort.setText(settingVo.proxyPort)
|
||||
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
|
||||
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
|
||||
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
binding!!.sbProxyAuthenticator.setOnCheckedChangeListener(this)
|
||||
binding!!.rgProxyType.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int ->
|
||||
if (checkedId == R.id.rb_proxyHttp || checkedId == R.id.rb_proxySocks) {
|
||||
binding!!.layoutProxyHost.visibility = View.VISIBLE
|
||||
binding!!.layoutProxyPort.visibility = View.VISIBLE
|
||||
binding!!.layoutProxyAuthenticator.visibility = if (binding!!.sbProxyAuthenticator.isChecked) View.VISIBLE else View.GONE
|
||||
} else {
|
||||
binding!!.layoutProxyHost.visibility = View.GONE
|
||||
binding!!.layoutProxyPort.visibility = View.GONE
|
||||
binding!!.layoutProxyAuthenticator.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
binding!!.rgMsgType.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int ->
|
||||
binding!!.layoutCustomTemplate.visibility = if (checkedId == R.id.rb_msg_type_markdown) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
|
||||
when (buttonView.id) {
|
||||
R.id.sb_proxyAuthenticator -> {
|
||||
binding!!.layoutProxyAuthenticator.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@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))
|
||||
DingtalkInnerRobotUtils.sendMsg(settingVo, msgInfo)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
if (Looper.myLooper() == null) Looper.prepare()
|
||||
XToastUtils.error(e.message.toString())
|
||||
Looper.loop()
|
||||
}
|
||||
}.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(): DingtalkInnerRobotSetting {
|
||||
val agentID = binding!!.etAgentID.text.toString().trim()
|
||||
val appKey = binding!!.etAppKey.text.toString().trim()
|
||||
val appSecret = binding!!.etAppSecret.text.toString().trim()
|
||||
val userIds = binding!!.etUserIds.text.toString().trim()
|
||||
if (TextUtils.isEmpty(agentID) || TextUtils.isEmpty(appKey) || TextUtils.isEmpty(appSecret) || TextUtils.isEmpty(userIds)) {
|
||||
throw Exception(getString(R.string.invalid_dingtalk_inner_robot))
|
||||
}
|
||||
|
||||
val proxyType: Proxy.Type = when (binding!!.rgProxyType.checkedRadioButtonId) {
|
||||
R.id.rb_proxyHttp -> Proxy.Type.HTTP
|
||||
R.id.rb_proxySocks -> Proxy.Type.SOCKS
|
||||
else -> Proxy.Type.DIRECT
|
||||
}
|
||||
val proxyHost = binding!!.etProxyHost.text.toString().trim()
|
||||
val proxyPort = binding!!.etProxyPort.text.toString().trim()
|
||||
|
||||
if (proxyType != Proxy.Type.DIRECT && (TextUtils.isEmpty(proxyHost) || TextUtils.isEmpty(proxyPort))) {
|
||||
throw Exception(getString(R.string.invalid_host_or_port))
|
||||
}
|
||||
|
||||
val proxyAuthenticator = binding!!.sbProxyAuthenticator.isChecked
|
||||
val proxyUsername = binding!!.etProxyUsername.text.toString().trim()
|
||||
val proxyPassword = binding!!.etProxyPassword.text.toString().trim()
|
||||
if (proxyAuthenticator && TextUtils.isEmpty(proxyUsername) && TextUtils.isEmpty(proxyPassword)) {
|
||||
throw Exception(getString(R.string.invalid_username_or_password))
|
||||
}
|
||||
|
||||
val msgKey = if (binding!!.rgMsgType.checkedRadioButtonId == R.id.rb_msg_type_markdown) "sampleMarkdown" else "sampleText"
|
||||
val titleTemplate = binding!!.etTitleTemplate.text.toString().trim()
|
||||
|
||||
return DingtalkInnerRobotSetting(agentID, appKey, appSecret, userIds, msgKey, titleTemplate, proxyType, proxyHost, proxyPort, proxyAuthenticator, proxyUsername, proxyPassword)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
if (mCountDownHelper != null) mCountDownHelper!!.recycle()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
}
|
@ -148,7 +148,7 @@ val BARK_LEVEL_MAP = mapOf(
|
||||
)
|
||||
|
||||
//发送通道
|
||||
const val TYPE_DINGDING = 0
|
||||
const val TYPE_DINGTALK_GROUP_ROBOT = 0
|
||||
const val TYPE_EMAIL = 1
|
||||
const val TYPE_BARK = 2
|
||||
const val TYPE_WEBHOOK = 3
|
||||
@ -160,8 +160,9 @@ const val TYPE_SMS = 8
|
||||
const val TYPE_FEISHU = 9
|
||||
const val TYPE_PUSHPLUS = 10
|
||||
const val TYPE_GOTIFY = 11
|
||||
const val TYPE_DINGTALK_INNER_ROBOT = 12
|
||||
var SENDER_FRAGMENT_LIST = listOf(
|
||||
PageInfo(getString(R.string.dingtalk_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkFragment", "{\"\":\"\"}", 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.bark), "com.idormy.sms.forwarder.fragment.senders.BarkFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_bark),
|
||||
PageInfo(getString(R.string.webhook), "com.idormy.sms.forwarder.fragment.senders.WebhookFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_webhook),
|
||||
@ -173,6 +174,7 @@ var SENDER_FRAGMENT_LIST = listOf(
|
||||
PageInfo(getString(R.string.feishu), "com.idormy.sms.forwarder.fragment.senders.FeishuFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_feishu),
|
||||
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.dingtalk_inner_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkInnerRobotFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_dingtalk_inner),
|
||||
)
|
||||
|
||||
//前台服务
|
||||
|
@ -3,6 +3,7 @@ package com.idormy.sms.forwarder.utils
|
||||
|
||||
import android.text.TextUtils
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.core.Core
|
||||
@ -136,7 +137,11 @@ class HttpServerUtils private constructor() {
|
||||
}
|
||||
|
||||
val sign = calcSign(req.timestamp.toString(), signSecret.toString())
|
||||
if (sign != req.sign) throw HttpException(500, getString(R.string.sign_verify_failed))
|
||||
if (sign != req.sign) {
|
||||
Log.e("calcSign", sign)
|
||||
Log.e("reqSign", req.sign.toString())
|
||||
throw HttpException(500, getString(R.string.sign_verify_failed))
|
||||
}
|
||||
}
|
||||
|
||||
//判断版本是否一致
|
||||
|
@ -71,9 +71,9 @@ object SendUtils {
|
||||
fun sendMsgSender(msgInfo: MsgInfo, rule: Rule, sender: Sender, logId: Long) {
|
||||
try {
|
||||
when (sender.type) {
|
||||
TYPE_DINGDING -> {
|
||||
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkSetting::class.java)
|
||||
DingtalkUtils.sendMsg(settingVo, msgInfo, rule, logId)
|
||||
TYPE_DINGTALK_GROUP_ROBOT -> {
|
||||
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkGroupRobotSetting::class.java)
|
||||
DingtalkGroupRobotUtils.sendMsg(settingVo, msgInfo, rule, logId)
|
||||
}
|
||||
TYPE_EMAIL -> {
|
||||
val settingVo = Gson().fromJson(sender.jsonSetting, EmailSetting::class.java)
|
||||
|
@ -7,7 +7,7 @@ import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.database.entity.Rule
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
import com.idormy.sms.forwarder.entity.result.DingtalkResult
|
||||
import com.idormy.sms.forwarder.entity.setting.DingtalkSetting
|
||||
import com.idormy.sms.forwarder.entity.setting.DingtalkGroupRobotSetting
|
||||
import com.idormy.sms.forwarder.utils.SendUtils
|
||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||
import com.xuexiang.xhttp2.XHttp
|
||||
@ -19,14 +19,15 @@ import java.nio.charset.StandardCharsets
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
//钉钉群自定义机器人
|
||||
@Suppress("PrivatePropertyName", "UNUSED_PARAMETER")
|
||||
class DingtalkUtils private constructor() {
|
||||
class DingtalkGroupRobotUtils private constructor() {
|
||||
companion object {
|
||||
|
||||
private val TAG: String = DingtalkUtils::class.java.simpleName
|
||||
private val TAG: String = DingtalkGroupRobotUtils::class.java.simpleName
|
||||
|
||||
fun sendMsg(
|
||||
setting: DingtalkSetting,
|
||||
setting: DingtalkGroupRobotSetting,
|
||||
msgInfo: MsgInfo,
|
||||
rule: Rule?,
|
||||
logId: Long?,
|
||||
@ -114,7 +115,7 @@ class DingtalkUtils private constructor() {
|
||||
|
||||
}
|
||||
|
||||
fun sendMsg(setting: DingtalkSetting, msgInfo: MsgInfo) {
|
||||
fun sendMsg(setting: DingtalkGroupRobotSetting, msgInfo: MsgInfo) {
|
||||
sendMsg(setting, msgInfo, null, null)
|
||||
}
|
||||
}
|
@ -0,0 +1,242 @@
|
||||
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.DingtalkInnerRobotResult
|
||||
import com.idormy.sms.forwarder.entity.setting.DingtalkInnerRobotSetting
|
||||
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
|
||||
import com.xuexiang.xutil.net.NetworkUtils
|
||||
import okhttp3.Credentials
|
||||
import okhttp3.Response
|
||||
import okhttp3.Route
|
||||
import java.net.Authenticator
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.PasswordAuthentication
|
||||
import java.net.Proxy
|
||||
|
||||
//钉钉企业内机器人
|
||||
@Suppress("PrivatePropertyName", "UNUSED_PARAMETER")
|
||||
class DingtalkInnerRobotUtils private constructor() {
|
||||
companion object {
|
||||
|
||||
private val TAG: String = DingtalkInnerRobotUtils::class.java.simpleName
|
||||
|
||||
fun sendMsg(
|
||||
setting: DingtalkInnerRobotSetting,
|
||||
msgInfo: MsgInfo,
|
||||
rule: Rule?,
|
||||
logId: Long?,
|
||||
) {
|
||||
|
||||
val accessToken: String? = MMKVUtils.getString("accessToken_" + setting.agentID, "")
|
||||
val expiresIn: Long = MMKVUtils.getLong("expiresIn_" + setting.agentID, 0L)
|
||||
if (!TextUtils.isEmpty(accessToken) && expiresIn > System.currentTimeMillis()) {
|
||||
return sendTextMsg(setting, msgInfo, rule, logId)
|
||||
}
|
||||
|
||||
val requestUrl = "https://api.dingtalk.com/v1.0/oauth2/accessToken"
|
||||
Log.d(TAG, "requestUrl:$requestUrl")
|
||||
|
||||
val msgMap: MutableMap<String, Any> = mutableMapOf()
|
||||
msgMap["appKey"] = setting.appKey
|
||||
msgMap["appSecret"] = setting.appSecret
|
||||
val requestMsg: String = Gson().toJson(msgMap)
|
||||
Log.i(TAG, "requestMsg:$requestMsg")
|
||||
|
||||
val request = XHttp.post(requestUrl)
|
||||
|
||||
//设置代理
|
||||
if ((setting.proxyType == Proxy.Type.HTTP || setting.proxyType == Proxy.Type.SOCKS)
|
||||
&& !TextUtils.isEmpty(setting.proxyHost) && !TextUtils.isEmpty(setting.proxyPort)
|
||||
) {
|
||||
//代理服务器的IP和端口号
|
||||
Log.d(TAG, "proxyHost = ${setting.proxyHost}, proxyPort = ${setting.proxyPort}")
|
||||
val proxyHost = if (NetworkUtils.isIP(setting.proxyHost)) setting.proxyHost else NetworkUtils.getDomainAddress(setting.proxyHost)
|
||||
if (!NetworkUtils.isIP(proxyHost)) {
|
||||
throw Exception("代理服务器主机名解析失败:proxyHost=$proxyHost")
|
||||
}
|
||||
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890
|
||||
|
||||
Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
|
||||
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))
|
||||
|
||||
//代理的鉴权账号密码
|
||||
if (setting.proxyAuthenticator == true
|
||||
&& (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))
|
||||
) {
|
||||
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")
|
||||
|
||||
if (setting.proxyType == Proxy.Type.HTTP) {
|
||||
request.okproxyAuthenticator { _: Route?, response: Response ->
|
||||
//设置代理服务器账号密码
|
||||
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
|
||||
response.request().newBuilder()
|
||||
.header("Proxy-Authorization", credential)
|
||||
.build()
|
||||
}
|
||||
} else {
|
||||
Authenticator.setDefault(object : Authenticator() {
|
||||
override fun getPasswordAuthentication(): PasswordAuthentication {
|
||||
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.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, DingtalkInnerRobotResult::class.java)
|
||||
if (!TextUtils.isEmpty(resp.accessToken)) {
|
||||
MMKVUtils.put("accessToken_" + setting.agentID, resp.accessToken)
|
||||
MMKVUtils.put("expiresIn_" + setting.agentID, System.currentTimeMillis() + ((resp.expireIn ?: 7200) - 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: DingtalkInnerRobotSetting,
|
||||
msgInfo: MsgInfo,
|
||||
rule: Rule?,
|
||||
logId: Long?,
|
||||
) {
|
||||
val requestUrl = "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend"
|
||||
Log.d(TAG, "requestUrl:$requestUrl")
|
||||
|
||||
val content: String = if (rule != null) {
|
||||
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)
|
||||
} else {
|
||||
msgInfo.getContentForSend(SettingUtils.smsTemplate.toString())
|
||||
}
|
||||
|
||||
val msgParam: MutableMap<String, Any> = mutableMapOf()
|
||||
if ("sampleMarkdown" == setting.msgKey) {
|
||||
msgParam["title"] = if (rule != null) {
|
||||
msgInfo.getTitleForSend(setting.titleTemplate.toString(), rule.regexReplace)
|
||||
} else {
|
||||
msgInfo.getTitleForSend(setting.titleTemplate.toString())
|
||||
}
|
||||
msgParam["text"] = content
|
||||
} else {
|
||||
msgParam["content"] = content
|
||||
}
|
||||
|
||||
val textMsgMap: MutableMap<String, Any> = mutableMapOf()
|
||||
textMsgMap["robotCode"] = setting.appKey
|
||||
textMsgMap["userIds"] = setting.userIds.split('|').toTypedArray()
|
||||
textMsgMap["msgKey"] = setting.msgKey
|
||||
textMsgMap["msgParam"] = Gson().toJson(msgParam)
|
||||
|
||||
val requestMsg: String = Gson().toJson(textMsgMap)
|
||||
Log.i(TAG, "requestMsg:$requestMsg")
|
||||
|
||||
val request = XHttp.post(requestUrl)
|
||||
|
||||
//设置代理
|
||||
if ((setting.proxyType == Proxy.Type.HTTP || setting.proxyType == Proxy.Type.SOCKS)
|
||||
&& !TextUtils.isEmpty(setting.proxyHost) && !TextUtils.isEmpty(setting.proxyPort)
|
||||
) {
|
||||
//代理服务器的IP和端口号
|
||||
Log.d(TAG, "proxyHost = ${setting.proxyHost}, proxyPort = ${setting.proxyPort}")
|
||||
val proxyHost = if (NetworkUtils.isIP(setting.proxyHost)) setting.proxyHost else NetworkUtils.getDomainAddress(setting.proxyHost)
|
||||
if (!NetworkUtils.isIP(proxyHost)) {
|
||||
throw Exception("代理服务器主机名解析失败:proxyHost=$proxyHost")
|
||||
}
|
||||
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890
|
||||
|
||||
Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
|
||||
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))
|
||||
|
||||
//代理的鉴权账号密码
|
||||
if (setting.proxyAuthenticator == true
|
||||
&& (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))
|
||||
) {
|
||||
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")
|
||||
|
||||
if (setting.proxyType == Proxy.Type.HTTP) {
|
||||
request.okproxyAuthenticator { _: Route?, response: Response ->
|
||||
//设置代理服务器账号密码
|
||||
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
|
||||
response.request().newBuilder()
|
||||
.header("Proxy-Authorization", credential)
|
||||
.build()
|
||||
}
|
||||
} else {
|
||||
Authenticator.setDefault(object : Authenticator() {
|
||||
override fun getPasswordAuthentication(): PasswordAuthentication {
|
||||
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.upJson(requestMsg)
|
||||
.headers("x-acs-dingtalk-access-token", MMKVUtils.getString("accessToken_" + setting.agentID, ""))
|
||||
.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)
|
||||
|
||||
val resp = Gson().fromJson(response, DingtalkInnerRobotResult::class.java)
|
||||
if (!TextUtils.isEmpty(resp.processQueryKey)) {
|
||||
SendUtils.updateLogs(logId, 2, response)
|
||||
} else {
|
||||
SendUtils.updateLogs(logId, 0, response)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
fun sendMsg(setting: DingtalkInnerRobotSetting, msgInfo: MsgInfo) {
|
||||
sendMsg(setting, msgInfo, null, null)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
BIN
app/src/main/res/drawable/icon_dingtalk_inner.webp
Normal file
BIN
app/src/main/res/drawable/icon_dingtalk_inner.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,459 @@
|
||||
<?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="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:gravity="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/Agent_ID"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_agentID"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
app:met_clearButton="true" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/senderBarStyle"
|
||||
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:gravity="end"
|
||||
android:text="@string/appkey"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_appKey"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
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="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="@string/appsecret"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_appSecret"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
app:met_passWordButton="true" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/senderBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
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:gravity="end"
|
||||
android:text="@string/specified_member"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:text="@string/specified_member_tips2"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_userIds"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
app:met_clearButton="true" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/senderBarStyle"
|
||||
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/feishu_msg_type"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/rg_msg_type"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_msg_type_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:checked="true"
|
||||
android:text="@string/sampleText" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_msg_type_markdown"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/sampleMarkdown" />
|
||||
|
||||
</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"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
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/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
|
||||
style="@style/senderBarStyle"
|
||||
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/proxy_settings"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/rg_proxyType"
|
||||
style="@style/rg_style"
|
||||
android:layout_marginStart="5dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_proxyNone"
|
||||
style="@style/rg_rb_style"
|
||||
android:checked="true"
|
||||
android:text="@string/proxy_none" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_proxyHttp"
|
||||
style="@style/rg_rb_style"
|
||||
android:text="@string/proxy_http" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_proxySocks"
|
||||
style="@style/rg_rb_style"
|
||||
android:text="@string/proxy_socks" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutProxyHost"
|
||||
style="@style/senderBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hostname" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_proxyHost"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
app:met_clearButton="true" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutProxyPort"
|
||||
style="@style/senderBarStyleWithSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/port" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_proxyPort"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:digits="0123456789"
|
||||
android:inputType="number"
|
||||
android:maxLength="5"
|
||||
android:singleLine="true"
|
||||
app:met_clearButton="true" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:text="@string/proxy_authenticator" />
|
||||
|
||||
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
||||
android:id="@+id/sb_proxyAuthenticator"
|
||||
style="@style/SwitchButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutProxyAuthenticator"
|
||||
style="@style/senderBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/username" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_proxyUsername"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
app:met_clearButton="true" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:text="@string/password" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_proxyPassword"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
app:met_passWordButton="true" />
|
||||
|
||||
</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>
|
@ -286,6 +286,7 @@
|
||||
<string name="invalid_webhook">WebHook is empty or not a valid URL</string>
|
||||
<string name="invalid_at_mobiles">Specified member cannot be empty or select @all</string>
|
||||
<string name="invalid_wework_agent">CoreID, AgentID, and Secret cannot be empty</string>
|
||||
<string name="invalid_dingtalk_inner_robot">AgentId, AppKey, AppSecret, and UserIds cannot be empty</string>
|
||||
<string name="invalid_phone_num">The receiving phone number cannot be empty</string>
|
||||
<string name="invalid_multi_match">Malformed multiple match rule line %s</string>
|
||||
<string name="invalid_regex_replace">Incorrect format on line %s of regex replacement</string>
|
||||
@ -314,6 +315,7 @@
|
||||
<string name="specified_member">Specified Member</string>
|
||||
<string name="at_all">\@all</string>
|
||||
<string name="specified_member_tips">Tip: List of member IDs that receive messages (multiple recipients are separated by \'|\', up to 1000)</string>
|
||||
<string name="specified_member_tips2">Tip: The userid of the user who receives the message, up to 20 at a time (separated by \'|\')</string>
|
||||
<string name="server_chan_send_key">SendKey</string>
|
||||
<string name="server_chan_channel">Message channel</string>
|
||||
<string name="server_chan_channel_tips">Tip: Dynamically specified, supports up to two channels, separated by a vertical bar |</string>
|
||||
@ -465,7 +467,8 @@
|
||||
<string name="priority">Priority(1 – 9)</string>
|
||||
<string name="_5">5</string>
|
||||
<string name="sb_rule_status">Enable this rule</string>
|
||||
<string name="dingtalk_robot">Dingtalk Bot</string>
|
||||
<string name="dingtalk_robot">Dingtalk Group Bot</string>
|
||||
<string name="dingtalk_inner_robot">Dingtalk Inner Bot</string>
|
||||
<string name="email">Email</string>
|
||||
<string name="bark">Bark</string>
|
||||
<string name="webhook">Webhook</string>
|
||||
@ -874,4 +877,8 @@
|
||||
<string name="silent_time_period">Silent (disable forwarding) time period</string>
|
||||
<string name="silent_time_period_tips">If the end time is less than the start time, it will span days; if it is equal, it will be disabled</string>
|
||||
<string name="download_frpc_tips">Do you want to download and restart to load!</string>
|
||||
<string name="appkey">AppKey</string>
|
||||
<string name="appsecret">AppSecret</string>
|
||||
<string name="sampleText">Sample Text</string>
|
||||
<string name="sampleMarkdown">Sample Markdown</string>
|
||||
</resources>
|
||||
|
@ -256,7 +256,7 @@
|
||||
<string name="delete_sender_toast">该条发送通道已经删除!</string>
|
||||
<string name="add_sender_title">选择发送通道类型</string>
|
||||
<string name="not_supported">暂不支持这种转发</string>
|
||||
<string name="setdingdingtitle">设置钉钉机器人</string>
|
||||
<string name="setdingdingtitle">设置钉钉群机器人</string>
|
||||
<string name="setemailtitle">设置邮箱</string>
|
||||
<string name="setwebnotifytitle">设置Webhook</string>
|
||||
<string name="setqywxgrouprobottitle">设置企业微信群机器人</string>
|
||||
@ -287,6 +287,7 @@
|
||||
<string name="invalid_webhook">WebHook为空 或 不是有效URL</string>
|
||||
<string name="invalid_at_mobiles">指定成员 不能为空 或者 选择@all</string>
|
||||
<string name="invalid_wework_agent">企业ID、AgentID、Secret都不能为空</string>
|
||||
<string name="invalid_dingtalk_inner_robot">AgentId、AppKey、AppSecret、UserIds都不能为空</string>
|
||||
<string name="invalid_phone_num">接收手机号不能为空</string>
|
||||
<string name="invalid_multi_match">多重匹配规则的第 %s 行格式有误</string>
|
||||
<string name="invalid_regex_replace">正则替换内容的第 %s 行格式有误</string>
|
||||
@ -315,6 +316,7 @@
|
||||
<string name="specified_member">指定成员</string>
|
||||
<string name="at_all">\@all</string>
|
||||
<string name="specified_member_tips">Tip:接收消息的成员ID列表(多个接收者用‘|’分隔,最多支持1000个)</string>
|
||||
<string name="specified_member_tips2">Tip:接收用户的userid,每次最多传20个(用‘|’分隔)</string>
|
||||
<string name="server_chan_send_key">SendKey</string>
|
||||
<string name="server_chan_channel">消息通道</string>
|
||||
<string name="server_chan_channel_tips">提示:动态指定,支持最多两个通道,用竖线|隔开</string>
|
||||
@ -466,7 +468,8 @@
|
||||
<string name="priority">优先级(1 – 9)</string>
|
||||
<string name="_5">5</string>
|
||||
<string name="sb_rule_status">启用该条转发规则</string>
|
||||
<string name="dingtalk_robot">钉钉机器人</string>
|
||||
<string name="dingtalk_robot">钉钉群机器人</string>
|
||||
<string name="dingtalk_inner_robot">钉钉企业机器人</string>
|
||||
<string name="email">电子邮箱</string>
|
||||
<string name="bark">Bark</string>
|
||||
<string name="webhook">Webhook</string>
|
||||
@ -875,4 +878,8 @@
|
||||
<string name="silent_time_period">免打扰(禁用转发)时间段</string>
|
||||
<string name="silent_time_period_tips">结束时间小于开始时间则跨天;相等则禁用</string>
|
||||
<string name="download_frpc_tips">是否立即下载,并重启加载?</string>
|
||||
<string name="appkey">AppKey</string>
|
||||
<string name="appsecret">AppSecret</string>
|
||||
<string name="sampleText">文本类型</string>
|
||||
<string name="sampleMarkdown">Markdown类型</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user