mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-03 01:17:41 +08:00
parent
0a651b2da2
commit
51149c95cd
@ -19,6 +19,7 @@
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
|
@ -0,0 +1,10 @@
|
||||
package com.idormy.sms.forwarder.entity.task
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class SmsSetting(
|
||||
var description: String = "",
|
||||
var simSlot: Int = 1,
|
||||
var phoneNumbers: String = "",
|
||||
var msgContent: String = "",
|
||||
) : Serializable
|
@ -26,6 +26,7 @@ import com.idormy.sms.forwarder.databinding.FragmentTasksEditBinding
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.entity.task.TaskSetting
|
||||
import com.idormy.sms.forwarder.utils.*
|
||||
import com.idormy.sms.forwarder.utils.task.CronUtils
|
||||
import com.xuexiang.xaop.annotation.SingleClick
|
||||
import com.xuexiang.xpage.annotation.Page
|
||||
import com.xuexiang.xpage.base.XPageFragment
|
||||
@ -37,6 +38,7 @@ import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder
|
||||
import com.xuexiang.xui.utils.DensityUtils
|
||||
import com.xuexiang.xui.utils.WidgetUtils
|
||||
import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
import gatewayapps.crondroid.CronExpression
|
||||
import io.reactivex.SingleObserver
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
@ -214,6 +216,9 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
val taskNew = checkForm()
|
||||
if (isClone) taskNew.id = 0
|
||||
Log.d(TAG, taskNew.toString())
|
||||
//应用任务
|
||||
applyTask(taskNew)
|
||||
//保存任务
|
||||
viewModel.insertOrUpdate(taskNew)
|
||||
XToastUtils.success(R.string.tipSaveSuccess)
|
||||
popToBack()
|
||||
@ -254,6 +259,7 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
}
|
||||
Log.d(TAG, "initForm: $itemListConditions")
|
||||
conditionsAdapter.notifyDataSetChanged()
|
||||
binding!!.layoutAddCondition.visibility = if (itemListConditions.size >= MAX_SETTING_NUM) View.GONE else View.VISIBLE
|
||||
}
|
||||
if (task.actions.isNotEmpty()) {
|
||||
val actionList = Gson().fromJson(task.actions, Array<TaskSetting>::class.java).toMutableList()
|
||||
@ -262,6 +268,7 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
}
|
||||
Log.d(TAG, "initForm: $itemListActions")
|
||||
actionsAdapter.notifyDataSetChanged()
|
||||
binding!!.layoutAddAction.visibility = if (itemListActions.size >= MAX_SETTING_NUM) View.GONE else View.VISIBLE
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
@ -283,7 +290,23 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
if (itemListActions.size <= 0) {
|
||||
throw Exception("请添加执行动作")
|
||||
}
|
||||
taskType = itemListConditions[0].type
|
||||
|
||||
val lastExecTime = Date()
|
||||
var nextExecTime = Date()
|
||||
val firstCondition = itemListConditions[0]
|
||||
taskType = firstCondition.type
|
||||
|
||||
when (taskType) {
|
||||
TASK_CONDITION_CRON -> {
|
||||
//检查定时任务的时间设置
|
||||
val cronSetting = Gson().fromJson(firstCondition.setting, CronSetting::class.java)
|
||||
if (cronSetting.expression.isEmpty()) {
|
||||
throw Exception("请设置定时任务的时间")
|
||||
}
|
||||
val cronExpression = CronExpression(cronSetting.expression)
|
||||
nextExecTime = cronExpression.getNextValidTimeAfter(lastExecTime)
|
||||
}
|
||||
}
|
||||
|
||||
//拼接任务描述
|
||||
val description = StringBuilder()
|
||||
@ -293,12 +316,36 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
description.append(itemListActions.map { it.description }.toTypedArray().joinToString(","))
|
||||
|
||||
val status = if (binding!!.sbStatus.isChecked) STATUS_ON else STATUS_OFF
|
||||
return Task(taskId, taskType, taskName, description.toString(), Gson().toJson(itemListConditions), Gson().toJson(itemListActions), status)
|
||||
return Task(
|
||||
taskId,
|
||||
taskType,
|
||||
taskName,
|
||||
description.toString(),
|
||||
Gson().toJson(itemListConditions),
|
||||
Gson().toJson(itemListActions),
|
||||
status,
|
||||
lastExecTime,
|
||||
nextExecTime
|
||||
)
|
||||
}
|
||||
|
||||
//测试任务
|
||||
private fun testTask(task: Task) {
|
||||
}
|
||||
|
||||
//应用任务
|
||||
private fun applyTask(task: Task) {
|
||||
when (task.type) {
|
||||
//定时任务
|
||||
TASK_CONDITION_CRON -> {
|
||||
//取消旧任务的定时器
|
||||
CronUtils.cancelAlarm(task)
|
||||
//设置新的定时器
|
||||
CronUtils.scheduleAlarm(task)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SingleClick
|
||||
override fun onItemClick(itemView: View, widgetInfo: PageInfo, pos: Int) {
|
||||
try {
|
||||
@ -394,6 +441,7 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
itemListConditions[requestCode - 1] = taskSetting
|
||||
}
|
||||
conditionsAdapter.notifyDataSetChanged()
|
||||
binding!!.layoutAddCondition.visibility = if (itemListConditions.size >= MAX_SETTING_NUM) View.GONE else View.VISIBLE
|
||||
} else if (resultCode in KEY_BACK_CODE_ACTION..KEY_BACK_CODE_ACTION + 999) {
|
||||
setting = extras!!.getString(KEY_BACK_DATA_ACTION)
|
||||
if (setting == null) return
|
||||
@ -448,6 +496,7 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
itemListActions[requestCode - 1] = taskSetting
|
||||
}
|
||||
actionsAdapter.notifyDataSetChanged()
|
||||
binding!!.layoutAddAction.visibility = if (itemListActions.size >= MAX_SETTING_NUM) View.GONE else View.VISIBLE
|
||||
}
|
||||
Log.d(TAG, "requestCode:$requestCode resultCode:$resultCode setting:$setting")
|
||||
}
|
||||
@ -487,6 +536,7 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
private fun removeCondition(position: Int) {
|
||||
itemListConditions.removeAt(position)
|
||||
conditionsAdapter.notifyItemRemoved(position)
|
||||
binding!!.layoutAddCondition.visibility = if (itemListConditions.size >= MAX_SETTING_NUM) View.GONE else View.VISIBLE
|
||||
}
|
||||
|
||||
private fun editAction(position: Int) {
|
||||
@ -507,5 +557,6 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
||||
private fun removeAction(position: Int) {
|
||||
itemListActions.removeAt(position)
|
||||
actionsAdapter.notifyItemRemoved(position)
|
||||
binding!!.layoutAddAction.visibility = if (itemListActions.size >= MAX_SETTING_NUM) View.GONE else View.VISIBLE
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ import android.view.ViewGroup
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksCronBinding
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksActionSendSmsBinding
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_ACTION
|
||||
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION
|
||||
@ -26,7 +26,7 @@ import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
|
||||
@Page(name = "Frpc")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class FrpcFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickListener {
|
||||
class FrpcFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), View.OnClickListener {
|
||||
|
||||
private val TAG: String = FrpcFragment::class.java.simpleName
|
||||
var titleBar: TitleBar? = null
|
||||
@ -46,12 +46,12 @@ class FrpcFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickList
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentTasksCronBinding {
|
||||
return FragmentTasksCronBinding.inflate(inflater, container, false)
|
||||
): FragmentTasksActionSendSmsBinding {
|
||||
return FragmentTasksActionSendSmsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_cron)
|
||||
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_frpc)
|
||||
return titleBar
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import android.view.ViewGroup
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksCronBinding
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksActionSendSmsBinding
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_ACTION
|
||||
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION
|
||||
@ -26,7 +26,7 @@ import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
|
||||
@Page(name = "HttpServer")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class HttpServerFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickListener {
|
||||
class HttpServerFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), View.OnClickListener {
|
||||
|
||||
private val TAG: String = HttpServerFragment::class.java.simpleName
|
||||
var titleBar: TitleBar? = null
|
||||
@ -46,12 +46,12 @@ class HttpServerFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnCli
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentTasksCronBinding {
|
||||
return FragmentTasksCronBinding.inflate(inflater, container, false)
|
||||
): FragmentTasksActionSendSmsBinding {
|
||||
return FragmentTasksActionSendSmsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_cron)
|
||||
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_server)
|
||||
return titleBar
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ class NotificationFragment : BaseFragment<FragmentRulesEditBinding?>(), View.OnC
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
titleBar = super.initTitle()!!.setImmersive(false)
|
||||
titleBar!!.setTitle(R.string.menu_rules)
|
||||
titleBar!!.setTitle(R.string.task_notification)
|
||||
return titleBar
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,32 @@
|
||||
package com.idormy.sms.forwarder.fragment.action
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.app.ActivityCompat
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.hjq.permissions.OnPermissionCallback
|
||||
import com.hjq.permissions.Permission
|
||||
import com.hjq.permissions.XXPermissions
|
||||
import com.idormy.sms.forwarder.App
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksCronBinding
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksActionSendSmsBinding
|
||||
import com.idormy.sms.forwarder.entity.task.SmsSetting
|
||||
import com.idormy.sms.forwarder.server.model.ConfigData
|
||||
import com.idormy.sms.forwarder.utils.EVENT_KEY_PHONE_NUMBERS
|
||||
import com.idormy.sms.forwarder.utils.EVENT_KEY_SIM_SLOT
|
||||
import com.idormy.sms.forwarder.utils.HttpServerUtils
|
||||
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_ACTION
|
||||
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION
|
||||
import com.idormy.sms.forwarder.utils.KEY_TEST_ACTION
|
||||
import com.idormy.sms.forwarder.utils.PhoneUtils
|
||||
import com.idormy.sms.forwarder.utils.TASK_ACTION_SENDSMS
|
||||
import com.idormy.sms.forwarder.utils.XToastUtils
|
||||
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||
@ -21,12 +34,15 @@ 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.xrouter.utils.TextUtils
|
||||
import com.xuexiang.xui.utils.CountDownButtonHelper
|
||||
import com.xuexiang.xui.utils.ResUtils
|
||||
import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
import com.xuexiang.xutil.XUtil
|
||||
|
||||
@Page(name = "SendSms")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class SendSmsFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickListener {
|
||||
@Suppress("PrivatePropertyName", "DEPRECATION")
|
||||
class SendSmsFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), View.OnClickListener {
|
||||
|
||||
private val TAG: String = SendSmsFragment::class.java.simpleName
|
||||
var titleBar: TitleBar? = null
|
||||
@ -36,8 +52,10 @@ class SendSmsFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickL
|
||||
@AutoWired(name = KEY_EVENT_DATA_ACTION)
|
||||
var eventData: String? = null
|
||||
|
||||
private var expression = "* * * * * ? *"
|
||||
private var description = "测试描述"
|
||||
private var description = ""
|
||||
private var simSlot = 1
|
||||
private var phoneNumbers = ""
|
||||
private var msgContent = ""
|
||||
|
||||
override fun initArgs() {
|
||||
XRouter.getInstance().inject(this)
|
||||
@ -46,18 +64,19 @@ class SendSmsFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickL
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentTasksCronBinding {
|
||||
return FragmentTasksCronBinding.inflate(inflater, container, false)
|
||||
): FragmentTasksActionSendSmsBinding {
|
||||
return FragmentTasksActionSendSmsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_cron)
|
||||
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_sendsms)
|
||||
return titleBar
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化控件
|
||||
*/
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun initViews() {
|
||||
//测试按钮增加倒计时,避免重复点击
|
||||
mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, 3)
|
||||
@ -71,11 +90,27 @@ class SendSmsFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickL
|
||||
}
|
||||
})
|
||||
|
||||
//卡槽信息
|
||||
val serverConfigStr = HttpServerUtils.serverConfig
|
||||
if (!TextUtils.isEmpty(serverConfigStr)) {
|
||||
val serverConfig: ConfigData = Gson().fromJson(serverConfigStr, object : TypeToken<ConfigData>() {}.type)
|
||||
binding!!.rbSimSlot1.text = "SIM1:" + serverConfig.extraSim1
|
||||
binding!!.rbSimSlot2.text = "SIM2:" + serverConfig.extraSim2
|
||||
}
|
||||
|
||||
Log.d(TAG, "initViews eventData:$eventData")
|
||||
if (eventData != null) {
|
||||
val settingVo = Gson().fromJson(eventData, CronSetting::class.java)
|
||||
val settingVo = Gson().fromJson(eventData, SmsSetting::class.java)
|
||||
Log.d(TAG, "initViews settingVo:$settingVo")
|
||||
|
||||
simSlot = settingVo.simSlot
|
||||
phoneNumbers = settingVo.phoneNumbers
|
||||
msgContent = settingVo.msgContent
|
||||
}
|
||||
|
||||
binding!!.rgSimSlot.check(if (simSlot == 1) R.id.rb_sim_slot_1 else R.id.rb_sim_slot_2)
|
||||
binding!!.etPhoneNumbers.setText(phoneNumbers)
|
||||
binding!!.etMsgContent.setText(msgContent)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@ -83,6 +118,12 @@ class SendSmsFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickL
|
||||
binding!!.btnTest.setOnClickListener(this)
|
||||
binding!!.btnDel.setOnClickListener(this)
|
||||
binding!!.btnSave.setOnClickListener(this)
|
||||
LiveEventBus.get(EVENT_KEY_SIM_SLOT, Int::class.java).observeSticky(this) { value: Int ->
|
||||
binding!!.rgSimSlot.check(if (value == 1) R.id.rb_sim_slot_2 else R.id.rb_sim_slot_1)
|
||||
}
|
||||
LiveEventBus.get(EVENT_KEY_PHONE_NUMBERS, String::class.java).observeSticky(this) { value: String ->
|
||||
binding!!.etPhoneNumbers.setText(value)
|
||||
}
|
||||
LiveEventBus.get(KEY_TEST_ACTION, String::class.java).observe(this) {
|
||||
mCountDownHelper?.finish()
|
||||
|
||||
@ -100,16 +141,45 @@ class SendSmsFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickL
|
||||
when (v.id) {
|
||||
R.id.btn_test -> {
|
||||
mCountDownHelper?.start()
|
||||
|
||||
//检查发送短信权限是否获取
|
||||
XXPermissions.with(this)
|
||||
.permission(Permission.SEND_SMS)
|
||||
.request(object : OnPermissionCallback {
|
||||
override fun onGranted(permissions: List<String>, all: Boolean) {
|
||||
Thread {
|
||||
try {
|
||||
val settingVo = checkSetting()
|
||||
Log.d(TAG, settingVo.toString())
|
||||
LiveEventBus.get(KEY_TEST_ACTION, String::class.java).post("success")
|
||||
|
||||
//获取卡槽信息
|
||||
if (App.SimInfoList.isEmpty()) {
|
||||
App.SimInfoList = PhoneUtils.getSimMultiInfo()
|
||||
}
|
||||
Log.d(TAG, App.SimInfoList.toString())
|
||||
|
||||
//发送卡槽: 1=SIM1, 2=SIM2
|
||||
val simSlotIndex = settingVo.simSlot - 1
|
||||
//TODO:取不到卡槽信息时,采用默认卡槽发送
|
||||
val mSubscriptionId: Int = App.SimInfoList[simSlotIndex]?.mSubscriptionId ?: -1
|
||||
|
||||
val msg = if (ActivityCompat.checkSelfPermission(XUtil.getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
|
||||
ResUtils.getString(R.string.no_sms_sending_permission)
|
||||
} else {
|
||||
PhoneUtils.sendSms(mSubscriptionId, settingVo.phoneNumbers, settingVo.msgContent) ?: "success"
|
||||
}
|
||||
LiveEventBus.get(KEY_TEST_ACTION, String::class.java).post(msg)
|
||||
} catch (e: Exception) {
|
||||
LiveEventBus.get(KEY_TEST_ACTION, String::class.java).post(e.message.toString())
|
||||
e.printStackTrace()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun onDenied(permissions: List<String>, never: Boolean) {
|
||||
LiveEventBus.get(KEY_TEST_ACTION, String::class.java).post(ResUtils.getString(R.string.no_sms_sending_permission))
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@ -135,7 +205,21 @@ class SendSmsFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickL
|
||||
|
||||
//检查设置
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun checkSetting(): CronSetting {
|
||||
return CronSetting(expression, description)
|
||||
private fun checkSetting(): SmsSetting {
|
||||
phoneNumbers = binding!!.etPhoneNumbers.text.toString().trim()
|
||||
if (!getString(R.string.phone_numbers_regex).toRegex().matches(phoneNumbers)) {
|
||||
throw Exception(getString(R.string.phone_numbers_error))
|
||||
}
|
||||
|
||||
msgContent = binding!!.etMsgContent.text.toString().trim()
|
||||
if (!getString(R.string.msg_content_regex).toRegex().matches(msgContent)) {
|
||||
throw Exception(getString(R.string.msg_content_error))
|
||||
}
|
||||
|
||||
simSlot = if (binding!!.rgSimSlot.checkedRadioButtonId == R.id.rb_sim_slot_2) 2 else 1
|
||||
|
||||
description = String.format(getString(R.string.send_sms_to), simSlot, phoneNumbers)
|
||||
|
||||
return SmsSetting(description, simSlot, phoneNumbers, msgContent)
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ import android.view.ViewGroup
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksCronBinding
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksActionSendSmsBinding
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_CONDITION
|
||||
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_CONDITION
|
||||
@ -26,7 +26,7 @@ import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
|
||||
@Page(name = "Battery")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class BatteryFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickListener {
|
||||
class BatteryFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), View.OnClickListener {
|
||||
|
||||
private val TAG: String = BatteryFragment::class.java.simpleName
|
||||
var titleBar: TitleBar? = null
|
||||
@ -46,8 +46,8 @@ class BatteryFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickL
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentTasksCronBinding {
|
||||
return FragmentTasksCronBinding.inflate(inflater, container, false)
|
||||
): FragmentTasksActionSendSmsBinding {
|
||||
return FragmentTasksActionSendSmsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
|
@ -9,7 +9,7 @@ import android.view.ViewGroup
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksCronBinding
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksActionSendSmsBinding
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_CONDITION
|
||||
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_CONDITION
|
||||
@ -26,7 +26,7 @@ import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
|
||||
@Page(name = "Charge")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class ChargeFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickListener {
|
||||
class ChargeFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), View.OnClickListener {
|
||||
|
||||
private val TAG: String = ChargeFragment::class.java.simpleName
|
||||
var titleBar: TitleBar? = null
|
||||
@ -46,8 +46,8 @@ class ChargeFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickLi
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentTasksCronBinding {
|
||||
return FragmentTasksCronBinding.inflate(inflater, container, false)
|
||||
): FragmentTasksActionSendSmsBinding {
|
||||
return FragmentTasksActionSendSmsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
|
@ -13,7 +13,7 @@ import android.widget.RadioGroup
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksCronBinding
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksConditionCronBinding
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_CONDITION
|
||||
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_CONDITION
|
||||
@ -37,7 +37,7 @@ import java.util.Locale
|
||||
|
||||
@Page(name = "Cron")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class CronFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickListener {
|
||||
class CronFragment : BaseFragment<FragmentTasksConditionCronBinding?>(), View.OnClickListener {
|
||||
|
||||
private val TAG: String = CronFragment::class.java.simpleName
|
||||
var titleBar: TitleBar? = null
|
||||
@ -87,8 +87,8 @@ class CronFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickList
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentTasksCronBinding {
|
||||
return FragmentTasksCronBinding.inflate(inflater, container, false)
|
||||
): FragmentTasksConditionCronBinding {
|
||||
return FragmentTasksConditionCronBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
|
@ -9,7 +9,7 @@ import android.view.ViewGroup
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksCronBinding
|
||||
import com.idormy.sms.forwarder.databinding.FragmentTasksActionSendSmsBinding
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_CONDITION
|
||||
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_CONDITION
|
||||
@ -26,7 +26,7 @@ import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
|
||||
@Page(name = "Network")
|
||||
@Suppress("PrivatePropertyName")
|
||||
class NetworkFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickListener {
|
||||
class NetworkFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), View.OnClickListener {
|
||||
|
||||
private val TAG: String = NetworkFragment::class.java.simpleName
|
||||
var titleBar: TitleBar? = null
|
||||
@ -46,8 +46,8 @@ class NetworkFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickL
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentTasksCronBinding {
|
||||
return FragmentTasksCronBinding.inflate(inflater, container, false)
|
||||
): FragmentTasksActionSendSmsBinding {
|
||||
return FragmentTasksActionSendSmsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
|
@ -4,20 +4,70 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.App
|
||||
import com.idormy.sms.forwarder.database.AppDatabase
|
||||
import com.idormy.sms.forwarder.database.entity.Task
|
||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||
import com.idormy.sms.forwarder.entity.task.TaskSetting
|
||||
import com.idormy.sms.forwarder.utils.task.CronUtils
|
||||
import gatewayapps.crondroid.CronExpression
|
||||
import java.util.Date
|
||||
|
||||
@Suppress("PropertyName")
|
||||
@Suppress("PropertyName", "DEPRECATION")
|
||||
class AlarmReceiver : BroadcastReceiver() {
|
||||
|
||||
val TAG: String = AlarmReceiver::class.java.simpleName
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val task = intent.getParcelableExtra<Task>("task")
|
||||
val task = intent.getParcelableExtra<Task>("TASK")
|
||||
if (task == null) {
|
||||
Log.d(TAG, "onReceive task is null")
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "onReceive task $task")
|
||||
Log.d(TAG, "lastExecTime = ${task.lastExecTime}, nextExecTime = ${task.nextExecTime}")
|
||||
try {
|
||||
//取消旧任务的定时器
|
||||
CronUtils.cancelAlarm(task)
|
||||
|
||||
// 根据任务信息执行相应操作
|
||||
if (task != null) {
|
||||
Log.d(TAG, "onReceive task $task")
|
||||
// 处理任务逻辑,例如执行特定操作或者更新界面
|
||||
}
|
||||
val conditionList = Gson().fromJson(task.conditions, Array<TaskSetting>::class.java).toMutableList()
|
||||
if (conditionList.isEmpty()) {
|
||||
Log.d(TAG, "onReceive conditionList is empty")
|
||||
return
|
||||
}
|
||||
val firstCondition = conditionList.firstOrNull()
|
||||
if (firstCondition == null) {
|
||||
Log.d(TAG, "onReceive firstCondition is null")
|
||||
return
|
||||
}
|
||||
val cronSetting = Gson().fromJson(firstCondition.setting, CronSetting::class.java)
|
||||
if (cronSetting == null) {
|
||||
Log.d(TAG, "onReceive cronSetting is null")
|
||||
return
|
||||
}
|
||||
// 更新任务的上次执行时间和下次执行时间
|
||||
val cronExpression = CronExpression(cronSetting.expression)
|
||||
task.lastExecTime = Date()
|
||||
task.nextExecTime = cronExpression.getNextValidTimeAfter(task.lastExecTime)
|
||||
Log.d(TAG, "lastExecTime = ${task.lastExecTime}, nextExecTime = ${task.nextExecTime}")
|
||||
// 自动禁用任务
|
||||
if (task.nextExecTime <= task.lastExecTime) {
|
||||
task.status = 0
|
||||
}
|
||||
// 更新任务信息
|
||||
AppDatabase.getInstance(App.context).taskDao().update(task)
|
||||
if (task.status == 0) {
|
||||
Log.d(TAG, "onReceive task is disabled")
|
||||
return
|
||||
}
|
||||
//设置新的定时器
|
||||
CronUtils.scheduleAlarm(task)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "onReceive error $e")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
@Suppress("PrivatePropertyName", "DeferredResultUnused", "OPT_IN_USAGE", "DEPRECATION")
|
||||
@Suppress("PrivatePropertyName", "DeferredResultUnused", "OPT_IN_USAGE", "DEPRECATION", "LiftReturnOrAssignment")
|
||||
class ForegroundService : Service() {
|
||||
|
||||
private val TAG: String = "ForegroundService"
|
||||
|
@ -482,6 +482,7 @@ var CLIENT_FRAGMENT_LIST = listOf(
|
||||
)
|
||||
|
||||
//自动任务
|
||||
const val MAX_SETTING_NUM = 5 //最大条件/动作设置条数
|
||||
const val KEY_TEST_CONDITION = "key_test_condition"
|
||||
const val KEY_EVENT_DATA_CONDITION = "event_data_condition"
|
||||
const val KEY_BACK_CODE_CONDITION = 1000
|
||||
|
@ -5,10 +5,10 @@ import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import com.idormy.sms.forwarder.database.entity.Task
|
||||
import com.idormy.sms.forwarder.receiver.AlarmReceiver
|
||||
|
||||
@Suppress("unused")
|
||||
class CronUtils {
|
||||
companion object {
|
||||
|
||||
@ -19,48 +19,51 @@ class CronUtils {
|
||||
this.context = context.applicationContext
|
||||
}
|
||||
|
||||
fun updateTaskAndScheduleAlarm(task: Task) {
|
||||
val oldTask = getOldTask(task.id) // 获取旧的任务信息
|
||||
cancelAlarm(oldTask) // 取消旧任务的定时器
|
||||
|
||||
updateTaskInDatabase(task) // 更新任务信息(例如,更新数据库中的任务信息)
|
||||
scheduleAlarm(task) // 设置新的定时器
|
||||
}
|
||||
|
||||
private fun cancelAlarm(task: Task?) {
|
||||
fun cancelAlarm(task: Task?) {
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val alarmIntent = Intent(context, AlarmReceiver::class.java)
|
||||
val requestCode = task?.id?.toInt() ?: -1
|
||||
|
||||
val pendingIntent = PendingIntent.getBroadcast(context, requestCode, alarmIntent, PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_IMMUTABLE)
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
requestCode,
|
||||
alarmIntent,
|
||||
PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_MUTABLE
|
||||
)
|
||||
pendingIntent?.let {
|
||||
alarmManager.cancel(it)
|
||||
it.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private fun scheduleAlarm(task: Task) {
|
||||
@SuppressLint("ScheduleExactAlarm")
|
||||
fun scheduleAlarm(task: Task) {
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val alarmIntent = Intent(context, AlarmReceiver::class.java)
|
||||
alarmIntent.putExtra("task", task)
|
||||
val requestCode = task.id.toInt()
|
||||
val pendingIntent = PendingIntent.getBroadcast(context, requestCode, alarmIntent, PendingIntent.FLAG_IMMUTABLE)
|
||||
//val now = Calendar.getInstance()
|
||||
val nextExecutionTime = task.nextExecTime.time
|
||||
alarmIntent.putExtra("TASK", task)
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
requestCode,
|
||||
alarmIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||
)
|
||||
|
||||
// TODO:设置闹钟,低电量模式下无法设置精确闹钟
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmManager.setExactAndAllowWhileIdle(
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
task.nextExecTime.time,
|
||||
pendingIntent
|
||||
)
|
||||
} else {
|
||||
alarmManager.setExact(
|
||||
AlarmManager.RTC_WAKEUP, nextExecutionTime, pendingIntent
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
task.nextExecTime.time,
|
||||
pendingIntent
|
||||
)
|
||||
}
|
||||
|
||||
private fun getOldTask(taskId: Long): Task {
|
||||
// 实现获取旧任务信息的逻辑
|
||||
// 返回旧任务信息(Task对象)
|
||||
return Task()
|
||||
}
|
||||
|
||||
private fun updateTaskInDatabase(task: Task) {
|
||||
// 实现更新数据库中任务信息的逻辑
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:contentDescription="@string/api_sms_send"
|
||||
app:srcCompat="@drawable/icon_api_sms_send" />
|
||||
app:srcCompat="@drawable/icon_api_sms_send"
|
||||
tools:ignore="ImageContrastCheck" />
|
||||
|
||||
<LinearLayout
|
||||
style="@style/senderBarStyle"
|
||||
@ -41,18 +42,21 @@
|
||||
<RadioGroup
|
||||
android:id="@+id/rg_sim_slot"
|
||||
style="@style/rg_style"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/config_padding_5dp">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_sim_slot_1"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:checked="true"
|
||||
android:text="@string/sim1" />
|
||||
android:text="@string/sim1"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_sim_slot_2"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:text="@string/sim2" />
|
||||
android:text="@string/sim2"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
@ -78,7 +82,8 @@
|
||||
app:met_clearButton="true"
|
||||
app:met_errorMessage="@string/phone_numbers_error"
|
||||
app:met_regexp="@string/phone_numbers_regex"
|
||||
app:met_validateOnFocusLost="true" />
|
||||
app:met_validateOnFocusLost="true"
|
||||
tools:ignore="TouchTargetSizeCheck,TextContrastCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -105,7 +110,8 @@
|
||||
app:met_maxCharacters="390"
|
||||
app:met_regexp="@string/msg_content_regex"
|
||||
app:met_validateOnFocusLost="true"
|
||||
app:mlet_hintText="@string/msg_content_hint" />
|
||||
app:mlet_hintText="@string/msg_content_hint"
|
||||
tools:ignore="TextContrastCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -126,7 +132,7 @@
|
||||
android:drawableStart="@drawable/ic_send_white"
|
||||
android:paddingStart="20dp"
|
||||
android:text="@string/send"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
tools:ignore="RtlSymmetry,TouchTargetSizeCheck,TextContrastCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
152
app/src/main/res/layout/fragment_tasks_action_send_sms.xml
Normal file
152
app/src/main/res/layout/fragment_tasks_action_send_sms.xml
Normal file
@ -0,0 +1,152 @@
|
||||
<?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:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
style="@style/senderBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sim_slot" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/rg_sim_slot"
|
||||
style="@style/rg_style"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/config_padding_5dp">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_sim_slot_1"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:checked="true"
|
||||
android:text="@string/sim1"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_sim_slot_2"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:text="@string/sim2"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/senderBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/phone_numbers" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_phone_numbers"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/phone_numbers_hint"
|
||||
android:singleLine="true"
|
||||
app:met_clearButton="true"
|
||||
app:met_errorMessage="@string/phone_numbers_error"
|
||||
app:met_regexp="@string/phone_numbers_regex"
|
||||
app:met_validateOnFocusLost="true"
|
||||
tools:ignore="TouchTargetSizeCheck,TextContrastCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/senderBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_content" />
|
||||
|
||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||
android:id="@+id/et_msg_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start|top"
|
||||
android:hint="@string/msg_content_hint"
|
||||
android:inputType="textMultiLine"
|
||||
app:met_clearButton="true"
|
||||
app:met_errorMessage="@string/msg_content_error"
|
||||
app:met_maxCharacters="390"
|
||||
app:met_regexp="@string/msg_content_regex"
|
||||
app:met_validateOnFocusLost="true"
|
||||
app:mlet_hintText="@string/msg_content_hint"
|
||||
tools:ignore="TextContrastCheck" />
|
||||
|
||||
</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/discard"
|
||||
android:textSize="11sp"
|
||||
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
|
||||
|
||||
<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/submit"
|
||||
android:textSize="11sp"
|
||||
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
|
||||
|
||||
<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,TextContrastCheck,TouchTargetSizeCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -262,6 +262,7 @@
|
||||
android:text="@string/test"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1108,8 +1108,8 @@
|
||||
<string name="task_network">Network</string>
|
||||
<string name="task_sendsms">Send Sms</string>
|
||||
<string name="task_notification">Notification</string>
|
||||
<string name="task_frpc">Frpc</string>
|
||||
<string name="task_server">HttpServer</string>
|
||||
<string name="task_frpc">Frpc Setting</string>
|
||||
<string name="task_server">Server Setting</string>
|
||||
|
||||
<string name="second">Second</string>
|
||||
<string name="minute">Minute</string>
|
||||
@ -1166,4 +1166,6 @@
|
||||
<string name="cron_expression_check">Cron Expression Test Result</string>
|
||||
<string name="invalid_cron_expression">Cron expression is invalid:\n%s</string>
|
||||
<string name="next_execution_times">The next %s execution times:\n%s</string>
|
||||
|
||||
<string name="send_sms_to">Use SIM-%s to send sms\n%s</string>
|
||||
</resources>
|
||||
|
@ -1109,8 +1109,8 @@
|
||||
<string name="task_network">网络状态</string>
|
||||
<string name="task_sendsms">发送短信</string>
|
||||
<string name="task_notification">通道推送</string>
|
||||
<string name="task_frpc">Frpc</string>
|
||||
<string name="task_server">HttpServer</string>
|
||||
<string name="task_frpc">设置 Frpc</string>
|
||||
<string name="task_server">设置 HttpServer</string>
|
||||
|
||||
<string name="second">秒</string>
|
||||
<string name="minute">分</string>
|
||||
@ -1167,4 +1167,6 @@
|
||||
<string name="cron_expression_check">Cron表达式测试结果</string>
|
||||
<string name="invalid_cron_expression">Cron表达式无效:\n%s</string>
|
||||
<string name="next_execution_times">最近 %s 次运行时间:\n%s</string>
|
||||
|
||||
<string name="send_sms_to">通过卡槽 SIM-%s 发送短信到:\n%s</string>
|
||||
</resources>
|
||||
|
@ -225,6 +225,7 @@
|
||||
</style>
|
||||
|
||||
<style name="rg_rb_style_match">
|
||||
<item name="android:layout_marginTop">5dp</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
|
Loading…
x
Reference in New Issue
Block a user