新增:自动任务·快捷指令 —— 执行动作:启停任务 #389

This commit is contained in:
pppscn 2024-02-26 13:39:54 +08:00
parent 2b091bbefe
commit 65ea7bcf0c
19 changed files with 989 additions and 7 deletions

View File

@ -0,0 +1,104 @@
package com.idormy.sms.forwarder.adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.adapter.base.ItemMoveCallback
import com.idormy.sms.forwarder.database.entity.Task
import java.util.Collections
@Suppress("DEPRECATION")
class TaskRecyclerAdapter(
var itemList: MutableList<Task>,
private var removeClickListener: ((Int) -> Unit)? = null,
private var editClickListener: ((Int) -> Unit)? = null,
) : RecyclerView.Adapter<TaskRecyclerAdapter.ViewHolder>(), ItemMoveCallback.Listener {
private lateinit var touchHelper: ItemTouchHelper
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.adapter_task_list_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = itemList[position]
holder.bind(item)
}
override fun getItemCount(): Int = itemList.size
fun setTouchHelper(touchHelper: ItemTouchHelper) {
this@TaskRecyclerAdapter.touchHelper = touchHelper
}
@SuppressLint("ClickableViewAccessibility")
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
private val image: ImageView = itemView.findViewById(R.id.iv_image)
private val status: ImageView = itemView.findViewById(R.id.iv_status)
private val title: TextView = itemView.findViewById(R.id.tv_title)
private val editIcon: ImageView = itemView.findViewById(R.id.iv_edit)
private val removeIcon: ImageView = itemView.findViewById(R.id.iv_remove)
private val dragIcon: ImageView = itemView.findViewById(R.id.iv_drag)
init {
if (removeClickListener == null) {
removeIcon.visibility = View.GONE
} else {
removeIcon.setOnClickListener(this)
}
if (editClickListener == null) {
editIcon.visibility = View.GONE
} else {
editIcon.setOnClickListener(this)
}
dragIcon.setOnTouchListener { _, event ->
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
touchHelper.startDrag(this)
}
return@setOnTouchListener false
}
}
fun bind(task: Task) {
image.setImageResource(task.imageId)
status.setImageResource(task.statusImageId)
title.text = task.name
}
override fun onClick(v: View?) {
val position = adapterPosition
if (position != RecyclerView.NO_POSITION) {
when (v?.id) {
R.id.iv_edit -> editClickListener?.let { it(position) }
R.id.iv_remove -> removeClickListener?.let { it(position) }
}
}
}
}
override fun onItemMove(fromPosition: Int, toPosition: Int) {
if (fromPosition < toPosition) {
for (i in fromPosition until toPosition) {
Collections.swap(itemList, i, i + 1)
}
} else {
for (i in fromPosition downTo toPosition + 1) {
Collections.swap(itemList, i, i - 1)
}
}
notifyItemMoved(fromPosition, toPosition)
}
override fun onDragFinished() {}
}

View File

@ -0,0 +1,167 @@
package com.idormy.sms.forwarder.adapter.spinner
import android.annotation.SuppressLint
import android.os.Build
import android.text.Html
import android.text.TextUtils
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.STATUS_OFF
import com.xuexiang.xui.utils.CollectionUtils
import com.xuexiang.xui.widget.spinner.editspinner.BaseEditSpinnerAdapter
import com.xuexiang.xui.widget.spinner.editspinner.EditSpinnerFilter
import com.xuexiang.xutil.resource.ResUtils.getDrawable
@Suppress("unused", "NAME_SHADOWING", "DEPRECATION")
class TaskSpinnerAdapter<T> : BaseEditSpinnerAdapter<T>, EditSpinnerFilter {
/**
* 选项的文字颜色
*/
private var mTextColor = 0
/**
* 选项的文字大小
*/
private var mTextSize = 0f
/**
* 背景颜色
*/
private var mBackgroundSelector = 0
/**
* 过滤关键词的选中颜色
*/
private var mFilterColor = "#F15C58"
private var mIsFilterKey = false
/**
* 构造方法
*
* @param data 选项数据
*/
constructor(data: List<T>?) : super(data)
/**
* 构造方法
*
* @param data 选项数据
*/
constructor(data: Array<T>?) : super(data)
override fun getEditSpinnerFilter(): EditSpinnerFilter {
return this
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
var convertView = convertView
val holder: ViewHolder
if (convertView == null) {
convertView = LayoutInflater.from(parent.context).inflate(R.layout.item_spinner_with_icon, parent, false)
holder = ViewHolder(convertView, mTextColor, mTextSize, mBackgroundSelector)
convertView.tag = holder
} else {
holder = convertView.tag as ViewHolder
}
val item = CollectionUtils.getListItem(mDataSource, mIndexs[position]) as TaskSpinnerItem
holder.iconView.setImageDrawable(item.icon)
holder.statusView.setImageDrawable(
getDrawable(
when (item.status) {
STATUS_OFF -> R.drawable.ic_stop
else -> R.drawable.ic_start
}
)
)
//holder.titleView.text = Html.fromHtml(item.toString())
holder.titleView.text = Html.fromHtml(getItem(position))
return convertView
}
override fun onFilter(keyword: String): Boolean {
mDisplayData.clear()
Log.d("TaskSpinnerAdapter", "keyword = $keyword")
Log.d("TaskSpinnerAdapter", "mIndexs.indices = ${mIndexs.indices}")
if (TextUtils.isEmpty(keyword)) {
initDisplayData(mDataSource)
for (i in mIndexs.indices) {
mIndexs[i] = i
}
} else {
try {
for (i in mDataSource.indices) {
if (getDataSourceString(i).contains(keyword, ignoreCase = true)) {
mIndexs[mDisplayData.size] = i
if (mIsFilterKey) {
mDisplayData.add(getDataSourceString(i).replaceFirst(keyword.toRegex(), "<font color=\"$mFilterColor\">$keyword</font>"))
} else {
mDisplayData.add(getDataSourceString(i))
}
}
}
} catch (e: Exception) {
e.printStackTrace()
Log.e("TaskSpinnerAdapter", "onFilter error: ${e.message}")
}
}
Log.d("TaskSpinnerAdapter", "mDisplayData = $mDisplayData")
notifyDataSetChanged()
return mDisplayData.size > 0
}
fun setTextColor(@ColorInt textColor: Int): TaskSpinnerAdapter<*> {
mTextColor = textColor
return this
}
fun setTextSize(textSize: Float): TaskSpinnerAdapter<*> {
mTextSize = textSize
return this
}
fun setBackgroundSelector(@DrawableRes backgroundSelector: Int): TaskSpinnerAdapter<*> {
mBackgroundSelector = backgroundSelector
return this
}
fun setFilterColor(filterColor: String): TaskSpinnerAdapter<*> {
mFilterColor = filterColor
return this
}
fun setIsFilterKey(isFilterKey: Boolean): TaskSpinnerAdapter<*> {
mIsFilterKey = isFilterKey
return this
}
@SuppressLint("ObsoleteSdkInt")
private class ViewHolder(convertView: View, @ColorInt textColor: Int, textSize: Float, @DrawableRes backgroundSelector: Int) {
val iconView: ImageView = convertView.findViewById(R.id.iv_icon)
val statusView: ImageView = convertView.findViewById(R.id.iv_status)
val titleView: TextView = convertView.findViewById(R.id.tv_title)
init {
if (textColor > 0) titleView.setTextColor(textColor)
if (textSize > 0F) titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
if (backgroundSelector != 0) titleView.setBackgroundResource(backgroundSelector)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
val config = convertView.resources.configuration
if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
titleView.textDirection = View.TEXT_DIRECTION_RTL
}
}
}
}
fun getItemSource(position: Int): T {
return mDataSource[mIndexs[position]]
}
}

View File

@ -0,0 +1,49 @@
package com.idormy.sms.forwarder.adapter.spinner
import android.graphics.drawable.Drawable
@Suppress("unused")
class TaskSpinnerItem(
var title: CharSequence,
var icon: Drawable? = null,
var id: Long? = 0L,
var status: Int? = 1
) {
fun setTitle(title: CharSequence): TaskSpinnerItem {
this.title = title
return this
}
fun setIcon(icon: Drawable?): TaskSpinnerItem {
this.icon = icon
return this
}
fun setId(id: Long): TaskSpinnerItem {
this.id = id
return this
}
fun setStatus(status: Int): TaskSpinnerItem {
this.status = status
return this
}
// 注意:自定义实体需要重写对象的 toString 方法
override fun toString(): String {
return title.toString()
}
companion object {
@JvmStatic
fun of(title: CharSequence): TaskSpinnerItem {
return TaskSpinnerItem(title)
}
@JvmStatic
fun arrayOf(vararg titles: CharSequence): Array<TaskSpinnerItem> {
return titles.map { TaskSpinnerItem(it) }.toTypedArray()
}
}
}

View File

@ -34,6 +34,9 @@ interface TaskDao {
@Query("UPDATE Task SET status = :status WHERE id = :id")
fun updateStatus(id: Long, status: Int)
@Query("UPDATE Task SET status=:status WHERE id IN (:ids)")
fun updateStatusByIds(ids: List<Long>, status: Int)
@Query("SELECT * FROM Task where id=:id")
fun get(id: Long): Single<Task>
@ -46,6 +49,9 @@ interface TaskDao {
@Query("SELECT * FROM Task where type >= 1000 ORDER BY id DESC")
fun pagingSourceMine(): PagingSource<Int, Task>
@Query("SELECT * FROM Task ORDER BY id DESC")
fun getAll(): Single<List<Task>>
@Transaction
@RawQuery(observedEntities = [Task::class])
fun getAllRaw(query: SupportSQLiteQuery): List<Task>

View File

@ -4,6 +4,7 @@ import androidx.annotation.WorkerThread
import androidx.sqlite.db.SimpleSQLiteQuery
import com.idormy.sms.forwarder.database.dao.TaskDao
import com.idormy.sms.forwarder.database.entity.Task
import io.reactivex.Single
import java.util.Date
class TaskRepository(private val taskDao: TaskDao) {
@ -20,10 +21,14 @@ class TaskRepository(private val taskDao: TaskDao) {
fun updateExecTime(taskId: Long, lastExecTime: Date, nextExecTime: Date, status: Int) = taskDao.updateExecTime(taskId, lastExecTime, nextExecTime, status)
fun updateStatusByIds(ids: List<Long>, status: Int) = taskDao.updateStatusByIds(ids, status)
fun get(id: Long) = taskDao.get(id)
suspend fun getOne(id: Long) = taskDao.getOne(id)
fun getAll(): Single<List<Task>> = taskDao.getAll()
fun getAllNonCache(): List<Task> {
val query = SimpleSQLiteQuery("SELECT * FROM Task ORDER BY id ASC")
return taskDao.getAllRaw(query)

View File

@ -0,0 +1,10 @@
package com.idormy.sms.forwarder.entity.action
import com.idormy.sms.forwarder.database.entity.Task
import java.io.Serializable
data class TaskActionSetting(
var description: String = "", //描述
var status: Int = 1, //状态0-禁用1-启用
var taskList: List<Task>, //自动任务列表
) : Serializable

View File

@ -208,6 +208,13 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
CoreAnim.slide,
R.drawable.auto_task_icon_resend
),
PageInfo(
getString(R.string.task_task),
"com.idormy.sms.forwarder.fragment.action.TaskActionFragment",
"{\"\":\"\"}",
CoreAnim.slide,
R.drawable.auto_task_icon_task
),
)
override fun initArgs() {

View File

@ -0,0 +1,303 @@
package com.idormy.sms.forwarder.fragment.action
import android.annotation.SuppressLint
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.work.Data
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.adapter.TaskRecyclerAdapter
import com.idormy.sms.forwarder.adapter.base.ItemMoveCallback
import com.idormy.sms.forwarder.adapter.spinner.TaskSpinnerAdapter
import com.idormy.sms.forwarder.adapter.spinner.TaskSpinnerItem
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Task
import com.idormy.sms.forwarder.databinding.FragmentTasksActionTaskBinding
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.action.TaskActionSetting
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_ACTION
import com.idormy.sms.forwarder.utils.KEY_BACK_DESCRIPTION_ACTION
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.STATUS_OFF
import com.idormy.sms.forwarder.utils.TASK_ACTION_TASK
import com.idormy.sms.forwarder.utils.TaskWorker
import com.idormy.sms.forwarder.utils.XToastUtils
import com.idormy.sms.forwarder.workers.ActionWorker
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.xutil.resource.ResUtils.getDrawable
import io.reactivex.SingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import java.util.Date
@Page(name = "Task")
@Suppress("PrivatePropertyName", "DEPRECATION")
class TaskActionFragment : BaseFragment<FragmentTasksActionTaskBinding?>(), View.OnClickListener {
private val TAG: String = TaskActionFragment::class.java.simpleName
private var titleBar: TitleBar? = null
private var mCountDownHelper: CountDownButtonHelper? = null
//所有自动任务下拉框
private var taskListAll = mutableListOf<Task>()
private val taskSpinnerList = mutableListOf<TaskSpinnerItem>()
private lateinit var taskSpinnerAdapter: TaskSpinnerAdapter<*>
//已选自动任务列表
private var taskId = 0L
private var taskListSelected = mutableListOf<Task>()
private lateinit var taskRecyclerView: RecyclerView
private lateinit var taskRecyclerAdapter: TaskRecyclerAdapter
@JvmField
@AutoWired(name = KEY_EVENT_DATA_ACTION)
var eventData: String? = null
override fun initArgs() {
XRouter.getInstance().inject(this)
}
override fun viewBindingInflate(
inflater: LayoutInflater,
container: ViewGroup,
): FragmentTasksActionTaskBinding {
return FragmentTasksActionTaskBinding.inflate(inflater, container, false)
}
override fun initTitle(): TitleBar? {
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_task)
return titleBar
}
/**
* 初始化控件
*/
override fun initViews() {
//测试按钮增加倒计时,避免重复点击
mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, 1)
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)
//获取自动任务列表
getTaskList()
}
})
Log.d(TAG, "initViews eventData:$eventData")
if (eventData != null) {
val settingVo = Gson().fromJson(eventData, TaskActionSetting::class.java)
binding!!.rgStatus.check(if (settingVo.status == 1) R.id.rb_status_enable else R.id.rb_status_disable)
Log.d(TAG, settingVo.taskList.toString())
settingVo.taskList.forEach {
taskId = it.id
taskListSelected.add(it)
}
Log.d(TAG, "initViews settingVo:$settingVo")
}
//初始化自动任务下拉框
initTask()
}
override fun onDestroyView() {
if (mCountDownHelper != null) mCountDownHelper!!.recycle()
super.onDestroyView()
}
@SuppressLint("SetTextI18n")
override fun initListeners() {
binding!!.btnTest.setOnClickListener(this)
binding!!.btnDel.setOnClickListener(this)
binding!!.btnSave.setOnClickListener(this)
}
@SingleClick
override fun onClick(v: View) {
try {
when (v.id) {
R.id.btn_test -> {
mCountDownHelper?.start()
try {
val settingVo = checkSetting()
Log.d(TAG, settingVo.toString())
val taskAction = TaskSetting(TASK_ACTION_TASK, getString(R.string.task_task), settingVo.description, Gson().toJson(settingVo), requestCode)
val taskActionsJson = Gson().toJson(arrayListOf(taskAction))
val msgInfo = MsgInfo("task", getString(R.string.task_task), settingVo.description, Date(), getString(R.string.task_task))
val actionData = Data.Builder().putLong(TaskWorker.taskId, 0).putString(TaskWorker.taskActions, taskActionsJson).putString(TaskWorker.msgInfo, Gson().toJson(msgInfo)).build()
val actionRequest = OneTimeWorkRequestBuilder<ActionWorker>().setInputData(actionData).build()
WorkManager.getInstance().enqueue(actionRequest)
} catch (e: Exception) {
mCountDownHelper?.finish()
e.printStackTrace()
Log.e(TAG, "onClick error: ${e.message}")
XToastUtils.error(e.message.toString(), 30000)
}
return
}
R.id.btn_del -> {
popToBack()
return
}
R.id.btn_save -> {
val settingVo = checkSetting()
val intent = Intent()
intent.putExtra(KEY_BACK_DESCRIPTION_ACTION, settingVo.description)
intent.putExtra(KEY_BACK_DATA_ACTION, Gson().toJson(settingVo))
setFragmentResult(TASK_ACTION_TASK, intent)
popToBack()
return
}
}
} catch (e: Exception) {
XToastUtils.error(e.message.toString(), 30000)
e.printStackTrace()
Log.e(TAG, "onClick error: ${e.message}")
}
}
//初始化自动任务
@SuppressLint("SetTextI18n", "NotifyDataSetChanged")
private fun initTask() {
//初始化自动任务下拉框
binding!!.spTask.setOnItemClickListener { _: AdapterView<*>, _: View, position: Int, _: Long ->
try {
val item = taskSpinnerAdapter.getItemSource(position) as TaskSpinnerItem
taskId = item.id!!
if (taskId > 0L) {
taskListSelected.forEach {
if (taskId == it.id) {
XToastUtils.warning(getString(R.string.task_contains_tips))
return@setOnItemClickListener
}
}
taskListAll.forEach {
if (taskId == it.id) {
taskListSelected.add(it)
}
}
taskRecyclerAdapter.notifyDataSetChanged()
}
} catch (e: Exception) {
XToastUtils.error(e.message.toString())
}
}
// 初始化已选自动任务列表 RecyclerView 和 Adapter
taskRecyclerView = binding!!.recyclerTasks
taskRecyclerAdapter = TaskRecyclerAdapter(taskListSelected, { position ->
taskListSelected.removeAt(position)
taskRecyclerAdapter.notifyItemRemoved(position)
taskRecyclerAdapter.notifyItemRangeChanged(position, taskListSelected.size) // 更新索引
})
taskRecyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = taskRecyclerAdapter
}
val taskMoveCallback = ItemMoveCallback(object : ItemMoveCallback.Listener {
override fun onItemMove(fromPosition: Int, toPosition: Int) {
Log.d(TAG, "onItemMove: $fromPosition $toPosition")
taskRecyclerAdapter.onItemMove(fromPosition, toPosition)
taskListSelected = taskRecyclerAdapter.itemList
}
override fun onDragFinished() {
taskListSelected = taskRecyclerAdapter.itemList
//taskRecyclerAdapter.notifyDataSetChanged()
Log.d(TAG, "onDragFinished: $taskListSelected")
}
})
val taskTouchHelper = ItemTouchHelper(taskMoveCallback)
taskTouchHelper.attachToRecyclerView(taskRecyclerView)
taskRecyclerAdapter.setTouchHelper(taskTouchHelper)
//获取自动任务列表
getTaskList()
}
//获取自动任务列表
private fun getTaskList() {
Core.task.getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Task>> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "getTaskList error: ${e.message}")
}
@SuppressLint("NotifyDataSetChanged")
override fun onSuccess(taskList: List<Task>) {
if (taskList.isEmpty()) {
XToastUtils.error(R.string.add_task_first)
return
}
taskSpinnerList.clear()
taskListAll = taskList as MutableList<Task>
for (task in taskList) {
val name = if (task.name.length > 20) task.name.substring(0, 19) else task.name
taskSpinnerList.add(TaskSpinnerItem(name, getDrawable(if (STATUS_OFF == task.status) task.greyImageId else task.imageId), task.id, task.status))
}
taskSpinnerAdapter = TaskSpinnerAdapter(taskSpinnerList).setIsFilterKey(true).setFilterColor("#EF5362").setBackgroundSelector(R.drawable.selector_custom_spinner_bg)
binding!!.spTask.setAdapter(taskSpinnerAdapter)
//taskSpinnerAdapter.notifyDataSetChanged()
//更新taskListSelected的状态与名称
taskListSelected.forEach {
taskListAll.forEach { task ->
if (it.id == task.id) {
//it.name = task.name
it.status = task.status
}
}
}
taskRecyclerAdapter.notifyDataSetChanged()
}
})
}
//检查设置
@SuppressLint("SetTextI18n")
private fun checkSetting(): TaskActionSetting {
if (taskListSelected.isEmpty() || taskId == 0L) {
throw Exception(getString(R.string.new_task_first))
}
val description = StringBuilder()
val status: Int
if (binding!!.rgStatus.checkedRadioButtonId == R.id.rb_status_enable) {
status = 1
description.append(getString(R.string.enable))
} else {
status = 0
description.append(getString(R.string.disable))
}
description.append(getString(R.string.menu_tasks)).append(", ").append(getString(R.string.specified_task)).append(": ")
description.append(taskListSelected.joinToString(",") { "[${it.id}]${it.name}" })
return TaskActionSetting(description.toString(), status, taskListSelected)
}
}

View File

@ -248,6 +248,7 @@ const val TASK_ACTION_RULE = 2006
const val TASK_ACTION_SENDER = 2007
const val TASK_ACTION_ALARM = 2008
const val TASK_ACTION_RESEND = 2009
const val TASK_ACTION_TASK = 2010
const val SP_BATTERY_INFO = "battery_info"
const val SP_BATTERY_STATUS = "battery_status"
@ -269,7 +270,7 @@ const val SP_LOCK_SCREEN_ACTION = "lock_screen_action"
const val DELAY_TIME_AFTER_SIM_READY = 5000L
//切换语言需要替换的自定义模板标签列表
val TAG_LANG = arrayOf("zh_CN", "zh_TW", "en")
//val TAG_LANG = arrayOf("zh_CN", "zh_TW", "en")
val TAG_LIST = arrayOf(
mapOf("zh_CN" to "{{来源号码}}", "zh_TW" to "{{來源號碼}}", "en" to "{{FROM}}"),
mapOf("zh_CN" to "{{短信内容}}", "zh_TW" to "{{簡訊內容}}", "en" to "{{SMS}}"),

View File

@ -25,6 +25,7 @@ import com.idormy.sms.forwarder.entity.action.RuleSetting
import com.idormy.sms.forwarder.entity.action.SenderSetting
import com.idormy.sms.forwarder.entity.action.SettingsSetting
import com.idormy.sms.forwarder.entity.action.SmsSetting
import com.idormy.sms.forwarder.entity.action.TaskActionSetting
import com.idormy.sms.forwarder.service.HttpServerService
import com.idormy.sms.forwarder.service.LocationService
import com.idormy.sms.forwarder.utils.CacheUtils
@ -49,6 +50,7 @@ import com.idormy.sms.forwarder.utils.TASK_ACTION_RULE
import com.idormy.sms.forwarder.utils.TASK_ACTION_SENDER
import com.idormy.sms.forwarder.utils.TASK_ACTION_SENDSMS
import com.idormy.sms.forwarder.utils.TASK_ACTION_SETTINGS
import com.idormy.sms.forwarder.utils.TASK_ACTION_TASK
import com.idormy.sms.forwarder.utils.TaskWorker
import com.idormy.sms.forwarder.utils.task.ConditionUtils
import com.jeremyliao.liveeventbus.LiveEventBus
@ -310,6 +312,22 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker
writeLog(String.format(getString(R.string.successful_execution), senderSetting.description), "SUCCESS")
}
TASK_ACTION_TASK -> {
val taskActionSetting = Gson().fromJson(action.setting, TaskActionSetting::class.java)
if (taskActionSetting == null) {
writeLog("taskActionSetting is null")
continue
}
val ids = taskActionSetting.taskList.map { it.id }
if (ids.isNotEmpty()) {
Core.task.updateStatusByIds(ids, taskActionSetting.status)
}
successNum++
writeLog(String.format(getString(R.string.successful_execution), taskActionSetting.description), "SUCCESS")
}
TASK_ACTION_ALARM -> {
val alarmSetting = Gson().fromJson(action.setting, AlarmSetting::class.java)
if (alarmSetting == null) {

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="25.0dip"
android:height="25.0dip"
android:autoMirrored="true"
android:viewportWidth="25.0"
android:viewportHeight="25.0">
<path
android:fillColor="#ff3482ff"
android:pathData="M6.66,0.66L18.66,0.66A6,6 0,0 1,24.66 6.66L24.66,18.66A6,6 0,0 1,18.66 24.66L6.66,24.66A6,6 0,0 1,0.66 18.66L0.66,6.66A6,6 0,0 1,6.66 0.66z" />
<group
android:scaleX="0.017"
android:scaleY="0.017"
android:translateX="4.6"
android:translateY="4.0">
<path
android:fillColor="#ffffff"
android:pathData="M920.2,668.1c0,33.3 -14.8,64.6 -40.7,85.6l-290.7,236.2c-54.4,45.4 -139.1,45.4 -193.6,0l-290.7,-236.2c-54,-42.2 -54,-129 0,-171.3L191.2,512 104.5,441.6c-54,-42.2 -54,-129.1 0,-171.3L395.2,34.1c54.4,-45.4 139.1,-45.4 193.6,0l290.7,236.2c54,42.2 54,129 0,171.3 -42.6,31.8 -90.4,-27.1 -50.5,-62.1a30.3,30.3 0,0 0,0 -47l-290.6,-236.2a73.8,73.8 0,0 0,-92.7 0l-290.6,236.2a30.3,30.3 0,0 0,0 47l290.6,236.2c26.9,21.8 65.9,21.8 92.7,0l0.4,-0.4 46.5,-36.5a40,40 0,0 1,49.5 62.8l-46.3,36.5c-54.4,45.3 -139,45.2 -193.3,-0.3L254.7,563.6 155,644.5a30.3,30.3 0,0 0,0 47l290.6,236.2c26.9,21.8 65.9,21.8 92.7,0l290.6,-236.2a30.3,30.3 0,0 0,0 -47l-290.6,-236.2a73.8,73.8 0,0 0,-92.7 0l-0.4,0.4 -46.5,36.6a40,40 0,0 1,-49.5 -62.8l46.2,-36.5C450,300.8 534.5,300.8 588.9,346.4l290.7,236.2c25.9,21 40.7,52.2 40.7,85.6z" />
</group>
</vector>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="25.0dip"
android:height="25.0dip"
android:autoMirrored="true"
android:viewportWidth="25.0"
android:viewportHeight="25.0">
<path
android:fillColor="#ffe6e6e6"
android:pathData="M6.66,0.66L18.66,0.66A6,6 0,0 1,24.66 6.66L24.66,18.66A6,6 0,0 1,18.66 24.66L6.66,24.66A6,6 0,0 1,0.66 18.66L0.66,6.66A6,6 0,0 1,6.66 0.66z" />
<group
android:scaleX="0.017"
android:scaleY="0.017"
android:translateX="4.6"
android:translateY="4.0">
<path
android:fillColor="#ffffffff"
android:pathData="M920.2,668.1c0,33.3 -14.8,64.6 -40.7,85.6l-290.7,236.2c-54.4,45.4 -139.1,45.4 -193.6,0l-290.7,-236.2c-54,-42.2 -54,-129 0,-171.3L191.2,512 104.5,441.6c-54,-42.2 -54,-129.1 0,-171.3L395.2,34.1c54.4,-45.4 139.1,-45.4 193.6,0l290.7,236.2c54,42.2 54,129 0,171.3 -42.6,31.8 -90.4,-27.1 -50.5,-62.1a30.3,30.3 0,0 0,0 -47l-290.6,-236.2a73.8,73.8 0,0 0,-92.7 0l-290.6,236.2a30.3,30.3 0,0 0,0 47l290.6,236.2c26.9,21.8 65.9,21.8 92.7,0l0.4,-0.4 46.5,-36.5a40,40 0,0 1,49.5 62.8l-46.3,36.5c-54.4,45.3 -139,45.2 -193.3,-0.3L254.7,563.6 155,644.5a30.3,30.3 0,0 0,0 47l290.6,236.2c26.9,21.8 65.9,21.8 92.7,0l290.6,-236.2a30.3,30.3 0,0 0,0 -47l-290.6,-236.2a73.8,73.8 0,0 0,-92.7 0l-0.4,0.4 -46.5,36.6a40,40 0,0 1,-49.5 -62.8l46.2,-36.5C450,300.8 534.5,300.8 588.9,346.4l290.7,236.2c25.9,21 40.7,52.2 40.7,85.6z" />
</group>
</vector>

View File

@ -3,7 +3,13 @@
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#BEC2C7"
android:pathData="M14,2H6C4.9,2 4.01,2.9 4.01,4L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8L14,2zM10.94,18L7.4,14.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L10.94,18zM13,9V3.5L18.5,9H13z" />
<group
android:scaleX="0.021"
android:scaleY="0.021"
android:translateX="1.7"
android:translateY="1.2">
<path
android:fillColor="#BEC2C7"
android:pathData="M920.2,668.1c0,33.3 -14.8,64.6 -40.7,85.6l-290.7,236.2c-54.4,45.4 -139.1,45.4 -193.6,0l-290.7,-236.2c-54,-42.2 -54,-129 0,-171.3L191.2,512 104.5,441.6c-54,-42.2 -54,-129.1 0,-171.3L395.2,34.1c54.4,-45.4 139.1,-45.4 193.6,0l290.7,236.2c54,42.2 54,129 0,171.3 -42.6,31.8 -90.4,-27.1 -50.5,-62.1a30.3,30.3 0,0 0,0 -47l-290.6,-236.2a73.8,73.8 0,0 0,-92.7 0l-290.6,236.2a30.3,30.3 0,0 0,0 47l290.6,236.2c26.9,21.8 65.9,21.8 92.7,0l0.4,-0.4 46.5,-36.5a40,40 0,0 1,49.5 62.8l-46.3,36.5c-54.4,45.3 -139,45.2 -193.3,-0.3L254.7,563.6 155,644.5a30.3,30.3 0,0 0,0 47l290.6,236.2c26.9,21.8 65.9,21.8 92.7,0l290.6,-236.2a30.3,30.3 0,0 0,0 -47l-290.6,-236.2a73.8,73.8 0,0 0,-92.7 0l-0.4,0.4 -46.5,36.6a40,40 0,0 1,-49.5 -62.8l46.2,-36.5C450,300.8 534.5,300.8 588.9,346.4l290.7,236.2c25.9,21 40.7,52.2 40.7,85.6z" />
</group>
</vector>

View File

@ -0,0 +1,87 @@
<?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="wrap_content"
android:background="@color/xui_config_color_white"
android:orientation="vertical"
tools:ignore="UseCompoundDrawables">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/xui_config_color_separator_light" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="@dimen/config_padding_5dp"
android:paddingBottom="@dimen/config_padding_5dp">
<LinearLayout
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_image"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/icon_dingtalk"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/iv_status"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginStart="14dp"
android:layout_marginTop="-10dp"
android:src="@drawable/ic_stop"
tools:ignore="ContentDescription,VisualLintBounds" />
</LinearLayout>
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:text="@string/dingtalk_robot"
android:textSize="@dimen/text_size_small"
android:textStyle="bold" />
<ImageView
android:id="@+id/iv_edit"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="5dp"
android:src="@drawable/ic_edit"
app:tint="@color/toast_info_color"
tools:ignore="ContentDescription,PrivateResource,ImageContrastCheck" />
<ImageView
android:id="@+id/iv_remove"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_delete"
app:tint="@color/toast_error_color"
tools:ignore="ContentDescription,PrivateResource" />
<ImageView
android:id="@+id/iv_drag"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="5dp"
android:src="@drawable/ic_drag"
app:tint="@color/colorStart"
tools:ignore="ContentDescription,ImageContrastCheck" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,148 @@
<?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">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_margin="10dp"
android:contentDescription="@string/task_task"
app:srcCompat="@drawable/auto_task_icon_task"
tools:ignore="ImageContrastCheck" />
<LinearLayout
style="@style/BarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/task_task"
android:textSize="@dimen/text_size_big"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/task_task_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="?attr/xui_config_color_separator_light" />
<RadioGroup
android:id="@+id/rg_status"
style="@style/rg_style"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/config_padding_5dp">
<RadioButton
android:id="@+id/rb_status_enable"
style="@style/rg_rb_style"
android:checked="true"
android:text="@string/enable"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton
android:id="@+id/rb_status_disable"
style="@style/rg_rb_style"
android:text="@string/disable"
tools:ignore="TouchTargetSizeCheck" />
</RadioGroup>
<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:layout_gravity="center_vertical"
android:text="@string/specified_task"
android:textStyle="bold" />
<com.xuexiang.xui.widget.spinner.editspinner.EditSpinner
android:id="@+id/sp_task"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
app:es_hint="@string/choose_task"
app:es_maxLength="20"
app:es_maxLine="1" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_tasks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/config_margin_5dp" />
</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.Spacing"
android:drawableStart="@drawable/ic_delete"
android:text="@string/discard"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_save"
style="@style/SuperButton.Blue.Icon.Spacing"
android:drawableStart="@drawable/ic_save"
android:text="@string/submit"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_test"
style="@style/SuperButton.Green.Icon.Spacing"
android:drawableStart="@drawable/ic_test"
android:text="@string/test"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
</LinearLayout>
</LinearLayout>

View File

@ -227,9 +227,11 @@
<string name="new_sender_first">Please add a new sender and then choose it.</string>
<string name="new_rule_first">Please add a new rule and then choose it.</string>
<string name="new_frpc_first">Please add a new frpc and then choose it.</string>
<string name="new_task_first">Please add a new task and then choose it.</string>
<string name="add_sender_first">Please add a sender first.</string>
<string name="add_rule_first">Please add a rule first.</string>
<string name="add_frpc_first">Please add a frpc first.</string>
<string name="add_task_first">Please add a task first.</string>
<string name="select_sender">Select Sender</string>
<string name="rule_tester">Rule tester:</string>
<string name="test_sim_slot">Test SIM Slot</string>
@ -830,6 +832,7 @@
<string name="choose_rule">Drop-down selection, keyword fuzzy match</string>
<string name="choose_sender">Drop-down selection, keyword fuzzy match</string>
<string name="choose_frpc">Drop-down selection, keyword fuzzy match</string>
<string name="choose_task">Drop-down selection, keyword fuzzy match</string>
<string name="choose_app">Installed Apps</string>
<string name="extra_app">Extra Apps</string>
<string name="extra_app_hint">One package name per line\nEnable async loading of the App list for selection.</string>
@ -982,6 +985,7 @@
<string name="sender_contains_tips">[Note] The sender is already in the list, no need to add it again!</string>
<string name="rule_contains_tips">[Note] The rule is already in the list, no need to add it again!</string>
<string name="frpc_contains_tips">[Note] The frpc is already in the list, no need to add it again!</string>
<string name="task_contains_tips">[Note] The task is already in the list, no need to add it again!</string>
<string name="local_call">Local Call:</string>
<string name="remote_sms">Remote SMS</string>
<string name="clear">Clear</string>
@ -1199,15 +1203,17 @@
<string name="task_settings">Settings</string>
<string name="task_settings_tips">Control the configuration switch of "Settings".</string>
<string name="task_rule">Rules On/Off</string>
<string name="task_rule_tips">Control enabling/disabling of "Rules"</string>
<string name="task_rule_tips">Control the enable/disable of "Rules"</string>
<string name="task_sender">Channels On/Off</string>
<string name="task_sender_tips">Control enabling/disabling of "Senders"</string>
<string name="task_sender_tips">Control the enable/disable of "Senders"</string>
<string name="task_alarm">Alarm</string>
<string name="task_alarm_tips">Alarm</string>
<string name="task_resend">Resend Message</string>
<string name="task_resend_tips">Resend forwarded records since N hours ago, 0=ALL</string>
<string name="task_resend_desc" formatted="false">Resend forwarding records since %s hours ago for %s</string>
<string name="task_resend_error">At least one "Original Result" must be selected</string>
<string name="task_task">Tasks On/Off</string>
<string name="task_task_tips">Control the enable/disable of the "Auto Task"</string>
<string name="second">Second</string>
<string name="minute">Minute</string>
@ -1323,6 +1329,8 @@
<string name="specified_rule_hint">Enter Rule IDs (comma-separated)</string>
<string name="specified_sender">Specified Sender</string>
<string name="specified_sender_hint">Enter Sender IDs (comma-separated)</string>
<string name="specified_task">Specified Task</string>
<string name="specified_task_hint">Enter Task IDs (comma-separated)</string>
<string name="current_language">English</string>
<string name="current_activity_language">Current Activity language: </string>

View File

@ -228,9 +228,11 @@
<string name="new_sender_first">请选择发送通道(若无,请先添加)</string>
<string name="new_rule_first">请选择发送通道(若无,请先添加)</string>
<string name="new_frpc_first">请选择发送通道(若无,请先添加)</string>
<string name="new_task_first">请选择自动任务(若无,请先添加)</string>
<string name="add_sender_first">请先去设置发送通道页面添加</string>
<string name="add_rule_first">请先去设置转发规则页面添加</string>
<string name="add_frpc_first">请先去设置FRPC页面添加</string>
<string name="add_task_first">请先去设置自动任务页面添加</string>
<string name="select_sender">发送通道</string>
<string name="rule_tester">转发规则测试</string>
<string name="test_sim_slot">测试模拟的接收卡槽</string>
@ -831,6 +833,7 @@
<string name="choose_rule">下拉选择,关键字模糊匹配</string>
<string name="choose_sender">下拉选择,关键字模糊匹配</string>
<string name="choose_frpc">下拉选择,关键字模糊匹配</string>
<string name="choose_task">下拉选择,关键字模糊匹配</string>
<string name="choose_app">已装APP列表</string>
<string name="extra_app">额外消除应用通知</string>
<string name="extra_app_hint">一行一个包名\n开启异步加载App列表以便选择</string>
@ -983,6 +986,7 @@
<string name="sender_contains_tips">【注意】该发送通道已经在列表中,无需重复添加!</string>
<string name="rule_contains_tips">【注意】该转发规则已经在列表中,无需重复添加!</string>
<string name="frpc_contains_tips">【注意】该Frpc已经在列表中无需重复添加</string>
<string name="task_contains_tips">【注意】该自动任务已经在列表中,无需重复添加!</string>
<string name="local_call">本地呼叫:</string>
<string name="remote_sms">远程发短信:</string>
<string name="clear">清除</string>
@ -1209,6 +1213,8 @@
<string name="task_resend_tips">自动重发N小时以来的转发记录0=全部</string>
<string name="task_resend_desc" formatted="false">自动重发%s小时以来%s的转发记录</string>
<string name="task_resend_error">必须至少选择一个【原转发状态】</string>
<string name="task_task">启停任务</string>
<string name="task_task_tips">控制【自动任务】的启用/禁用</string>
<string name="second"></string>
<string name="minute"></string>
@ -1324,6 +1330,8 @@
<string name="specified_rule_hint">填写转发规则的id多个以半角逗号分隔</string>
<string name="specified_sender">指定通道</string>
<string name="specified_sender_hint">填写发送通道的id多个以半角逗号分隔</string>
<string name="specified_task">指定任务</string>
<string name="specified_task_hint">填写自动任务的id多个以半角逗号分隔</string>
<string name="current_language">简体中文</string>
<string name="current_activity_language">当前 Activity 语种:</string>

View File

@ -228,9 +228,11 @@
<string name="new_sender_first">請選擇發送通道(若無,請先添加)</string>
<string name="new_rule_first">請選擇轉發規則(若無,請先添加)</string>
<string name="new_frpc_first">請選擇FRPC若無請先添加</string>
<string name="new_task_first">請選擇自動任務(若無,請先添加)</string>
<string name="add_sender_first">請先去設置發送通道頁面添加</string>
<string name="add_rule_first">請先去設置轉發規則頁面添加</string>
<string name="add_frpc_first">請先去設置FRPC頁面添加</string>
<string name="add_task_first">請先去設置自動任務頁面添加</string>
<string name="select_sender">發送通道</string>
<string name="rule_tester">轉發規則測試</string>
<string name="test_sim_slot">測試模擬的接收卡槽</string>
@ -831,6 +833,7 @@
<string name="choose_rule">下拉選擇,關鍵字模糊匹配</string>
<string name="choose_sender">下拉選擇,關鍵字模糊匹配</string>
<string name="choose_frpc">下拉選擇,關鍵字模糊匹配</string>
<string name="choose_task">下拉選擇,關鍵字模糊匹配</string>
<string name="choose_app">已裝APP列表</string>
<string name="extra_app">額外消除應用通知</string>
<string name="extra_app_hint">一行一個包名\n開啟異步加載App列表以便選擇</string>
@ -983,6 +986,7 @@
<string name="sender_contains_tips">【注意】該發送通道已經在列表中,無需重複添加!</string>
<string name="rule_contains_tips">【注意】該轉發規則已經在列表中,無需重複添加!</string>
<string name="frpc_contains_tips">【注意】該Frpc已經在列表中無需重複添加</string>
<string name="task_contains_tips">【注意】該自動任務已經在列表中,無需重複添加!</string>
<string name="local_call">本地呼叫:</string>
<string name="remote_sms">遠程發簡訊:</string>
<string name="clear">清除</string>
@ -1209,6 +1213,8 @@
<string name="task_resend_tips">自動重發N小時以來的轉發記錄0=全部</string>
<string name="task_resend_desc" formatted="false">自動重發%s小時以來%s的轉發記錄</string>
<string name="task_resend_error">必须至少选择一個「原轉發狀態」</string>
<string name="task_task">啟停任務</string>
<string name="task_task_tips">控制【自動任務】的啟用/禁用</string>
<string name="second"></string>
<string name="minute"></string>
@ -1324,7 +1330,8 @@
<string name="specified_rule_hint">填寫轉發規則的ID多個以半角逗號分隔</string>
<string name="specified_sender">指定通道</string>
<string name="specified_sender_hint">填寫發送通道的ID多個以半角逗號分隔</string>
<string name="specified_task">指定任務</string>
<string name="specified_task_hint">填寫自動任務的ID多個以半角逗號分隔</string>
<string name="current_language">繁體中文</string>
<string name="current_activity_language">當前 Activity 語種:</string>

View File

@ -228,9 +228,11 @@
<string name="new_sender_first">请选择发送通道(若无,请先添加)</string>
<string name="new_rule_first">请选择转发规则(若无,请先添加)</string>
<string name="new_frpc_first">请选择Frpc若无请先添加</string>
<string name="new_task_first">请选择自动任务(若无,请先添加)</string>
<string name="add_sender_first">请先去设置发送通道页面添加</string>
<string name="add_rule_first">请先去设置转发规则页面添加</string>
<string name="add_frpc_first">请先去设置Frpc页面添加</string>
<string name="add_task_first">请先去设置自动任务页面添加</string>
<string name="select_sender">发送通道</string>
<string name="rule_tester">转发规则测试</string>
<string name="test_sim_slot">测试模拟的接收卡槽</string>
@ -831,6 +833,7 @@
<string name="choose_rule">下拉选择,关键字模糊匹配</string>
<string name="choose_sender">下拉选择,关键字模糊匹配</string>
<string name="choose_frpc">下拉选择,关键字模糊匹配</string>
<string name="choose_task">下拉选择,关键字模糊匹配</string>
<string name="choose_app">已装APP列表</string>
<string name="extra_app">额外消除应用通知</string>
<string name="extra_app_hint">一行一个包名\n开启异步加载App列表以便选择</string>
@ -983,6 +986,7 @@
<string name="sender_contains_tips">【注意】该发送通道已经在列表中,无需重复添加!</string>
<string name="rule_contains_tips">【注意】该转发规则已经在列表中,无需重复添加!</string>
<string name="frpc_contains_tips">【注意】该Frpc已经在列表中无需重复添加</string>
<string name="task_contains_tips">【注意】该自动任务已经在列表中,无需重复添加!</string>
<string name="local_call">本地呼叫:</string>
<string name="remote_sms">远程发短信:</string>
<string name="clear">清除</string>
@ -1209,6 +1213,8 @@
<string name="task_resend_tips">自动重发N小时以来的转发记录0=全部</string>
<string name="task_resend_desc" formatted="false">自动重发%s小时以来%s的转发记录</string>
<string name="task_resend_error">必须至少选择一个【原转发状态】</string>
<string name="task_task">启停任务</string>
<string name="task_task_tips">控制【自动任务】的启用/禁用</string>
<string name="second"></string>
<string name="minute"></string>
@ -1324,6 +1330,8 @@
<string name="specified_rule_hint">填写转发规则的id多个以半角逗号分隔</string>
<string name="specified_sender">指定通道</string>
<string name="specified_sender_hint">填写发送通道的id多个以半角逗号分隔</string>
<string name="specified_task">指定任务</string>
<string name="specified_task_hint">填写发送通道的id多个以半角逗号分隔</string>
<string name="current_language">跟随系统</string>
<string name="current_activity_language">当前 Activity 语种:</string>