新增:自动任务·快捷指令

This commit is contained in:
pppscn 2023-12-03 22:55:09 +08:00
parent d10d831685
commit 1d1fb747fc
14 changed files with 393 additions and 473 deletions

View File

@ -62,11 +62,12 @@
<uses-permission
android:name="android.permission.REBOOT"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"
<uses-permission
android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<application
android:name=".App"
@ -120,6 +121,13 @@
android:launchMode="singleInstance"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan|stateHidden" />
<activity
android:name=".activity.TaskActivity"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:exported="true"
android:launchMode="singleInstance"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan|stateHidden" />
<!--通用浏览器-->
<activity
android:name=".core.webview.AgentWebActivity"
@ -259,6 +267,7 @@
<intent-filter android:priority="2147483647">
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
@ -280,6 +289,7 @@
<action android:name="android.intent.action.SIM_STATE_CHANGED" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.AlarmReceiver" />
</application>
</manifest>

View File

@ -0,0 +1,14 @@
package com.idormy.sms.forwarder.activity
import android.os.Bundle
import androidx.viewbinding.ViewBinding
import com.idormy.sms.forwarder.core.BaseActivity
import com.idormy.sms.forwarder.fragment.TasksEditFragment
class TaskActivity : BaseActivity<ViewBinding?>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
openPage(TasksEditFragment::class.java)
}
}

View File

@ -0,0 +1,132 @@
@file:Suppress("DEPRECATION")
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.entity.task.TaskSetting
class TaskSettingAdapter(
val itemList: MutableList<TaskSetting>,
private val editClickListener: (Int) -> Unit,
private val removeClickListener: (Int) -> Unit
) : RecyclerView.Adapter<TaskSettingAdapter.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_setting_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@TaskSettingAdapter.touchHelper = touchHelper
}
@SuppressLint("ClickableViewAccessibility")
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
private val icon: ImageView = itemView.findViewById(R.id.iv_icon)
private val title: TextView = itemView.findViewById(R.id.tv_title)
private val description: TextView = itemView.findViewById(R.id.tv_description)
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 {
editIcon.setOnClickListener(this)
removeIcon.setOnClickListener(this)
dragIcon.setOnTouchListener { _, event ->
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
touchHelper.startDrag(this)
}
return@setOnTouchListener false
}
}
fun bind(taskSetting: TaskSetting) {
icon.setImageResource(taskSetting.iconId)
title.text = taskSetting.title
description.text = taskSetting.description
}
override fun onClick(v: View?) {
val position = adapterPosition
if (position != RecyclerView.NO_POSITION) {
when (v?.id) {
R.id.iv_edit -> editClickListener(position)
R.id.iv_remove -> removeClickListener(position)
}
}
}
}
override fun onItemMove(fromPosition: Int, toPosition: Int) {
if (fromPosition < toPosition) {
for (i in fromPosition until toPosition) {
itemList[i] = itemList.set(i + 1, itemList[i])
}
} else {
for (i in fromPosition downTo toPosition + 1) {
itemList[i] = itemList.set(i - 1, itemList[i])
}
}
notifyItemMoved(fromPosition, toPosition)
}
override fun onDragFinished() {
TODO("Not yet implemented")
}
}
class ItemMoveCallback(private val listener: Listener) : ItemTouchHelper.Callback() {
interface Listener {
fun onItemMove(fromPosition: Int, toPosition: Int)
fun onDragFinished()
}
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
return makeMovementFlags(dragFlags, 0)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
listener.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
// Swiping is not needed for this example
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
listener.onDragFinished()
}
}
}

View File

@ -1,92 +0,0 @@
package com.idormy.sms.forwarder.adapter.spinner
import android.content.Context
import android.graphics.drawable.Drawable
import com.xuexiang.xui.utils.ResUtils
@Suppress("unused")
class ActionAdapterItem {
//标题内容
var title: CharSequence
//图标
var icon: Drawable? = null
//ID
var id: Long? = 0L
//状态
var status: Int? = 1
constructor(title: CharSequence) {
this.title = title
}
constructor(title: CharSequence, icon: Drawable?) {
this.title = title
this.icon = icon
}
constructor(title: CharSequence, icon: Drawable?, id: Long?) {
this.title = title
this.icon = icon
this.id = id
}
constructor(title: CharSequence, icon: Drawable?, id: Long?, status: Int?) {
this.title = title
this.icon = icon
this.id = id
this.status = status
}
constructor(title: CharSequence, drawableId: Int) : this(title, ResUtils.getDrawable(drawableId))
constructor(title: CharSequence, drawableId: Int, id: Long) : this(title, ResUtils.getDrawable(drawableId), id)
constructor(title: CharSequence, drawableId: Int, id: Long, status: Int) : this(title, ResUtils.getDrawable(drawableId), id, status)
constructor(context: Context?, titleId: Int, drawableId: Int) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId))
constructor(context: Context?, titleId: Int, drawableId: Int, id: Long) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId), id)
constructor(context: Context?, titleId: Int, drawableId: Int, id: Long, status: Int) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId), id, status)
constructor(context: Context?, title: CharSequence, drawableId: Int) : this(title, ResUtils.getDrawable(context, drawableId))
constructor(context: Context?, title: CharSequence, drawableId: Int, id: Long) : this(title, ResUtils.getDrawable(context, drawableId), id)
constructor(context: Context?, title: CharSequence, drawableId: Int, id: Long, status: Int) : this(title, ResUtils.getDrawable(context, drawableId), id, status)
fun setStatus(status: Int): ActionAdapterItem {
this.status = status
return this
}
fun setId(id: Long): ActionAdapterItem {
this.id = id
return this
}
fun setTitle(title: CharSequence): ActionAdapterItem {
this.title = title
return this
}
fun setIcon(icon: Drawable?): ActionAdapterItem {
this.icon = icon
return this
}
//注意自定义实体需要重写对象的toString方法
override fun toString(): String {
return title.toString()
}
companion object {
fun of(title: CharSequence): ActionAdapterItem {
return ActionAdapterItem(title)
}
fun arrayof(title: Array<CharSequence>): Array<ActionAdapterItem?> {
val array = arrayOfNulls<ActionAdapterItem>(title.size)
for (i in array.indices) {
array[i] = ActionAdapterItem(title[i])
}
return array
}
}
}

View File

@ -1,92 +0,0 @@
package com.idormy.sms.forwarder.adapter.spinner
import android.content.Context
import android.graphics.drawable.Drawable
import com.xuexiang.xui.utils.ResUtils
@Suppress("unused")
class ConditionAdapterItem {
//标题内容
var title: CharSequence
//图标
var icon: Drawable? = null
//ID
var id: Long? = 0L
//状态
var status: Int? = 1
constructor(title: CharSequence) {
this.title = title
}
constructor(title: CharSequence, icon: Drawable?) {
this.title = title
this.icon = icon
}
constructor(title: CharSequence, icon: Drawable?, id: Long?) {
this.title = title
this.icon = icon
this.id = id
}
constructor(title: CharSequence, icon: Drawable?, id: Long?, status: Int?) {
this.title = title
this.icon = icon
this.id = id
this.status = status
}
constructor(title: CharSequence, drawableId: Int) : this(title, ResUtils.getDrawable(drawableId))
constructor(title: CharSequence, drawableId: Int, id: Long) : this(title, ResUtils.getDrawable(drawableId), id)
constructor(title: CharSequence, drawableId: Int, id: Long, status: Int) : this(title, ResUtils.getDrawable(drawableId), id, status)
constructor(context: Context?, titleId: Int, drawableId: Int) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId))
constructor(context: Context?, titleId: Int, drawableId: Int, id: Long) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId), id)
constructor(context: Context?, titleId: Int, drawableId: Int, id: Long, status: Int) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId), id, status)
constructor(context: Context?, title: CharSequence, drawableId: Int) : this(title, ResUtils.getDrawable(context, drawableId))
constructor(context: Context?, title: CharSequence, drawableId: Int, id: Long) : this(title, ResUtils.getDrawable(context, drawableId), id)
constructor(context: Context?, title: CharSequence, drawableId: Int, id: Long, status: Int) : this(title, ResUtils.getDrawable(context, drawableId), id, status)
fun setStatus(status: Int): ConditionAdapterItem {
this.status = status
return this
}
fun setId(id: Long): ConditionAdapterItem {
this.id = id
return this
}
fun setTitle(title: CharSequence): ConditionAdapterItem {
this.title = title
return this
}
fun setIcon(icon: Drawable?): ConditionAdapterItem {
this.icon = icon
return this
}
//注意自定义实体需要重写对象的toString方法
override fun toString(): String {
return title.toString()
}
companion object {
fun of(title: CharSequence): ConditionAdapterItem {
return ConditionAdapterItem(title)
}
fun arrayof(title: Array<CharSequence>): Array<ConditionAdapterItem?> {
val array = arrayOfNulls<ConditionAdapterItem>(title.size)
for (i in array.indices) {
array[i] = ConditionAdapterItem(title[i])
}
return array
}
}
}

View File

@ -1,13 +1,14 @@
package com.idormy.sms.forwarder.entity.task
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.utils.TYPE_BARK
import com.idormy.sms.forwarder.utils.TYPE_DINGTALK_GROUP_ROBOT
import com.idormy.sms.forwarder.utils.TYPE_EMAIL
import com.idormy.sms.forwarder.utils.TASK_CONDITION_BATTERY
import com.idormy.sms.forwarder.utils.TASK_CONDITION_CHARGE
import com.idormy.sms.forwarder.utils.TASK_CONDITION_CRON
import com.idormy.sms.forwarder.utils.TASK_CONDITION_WLAN
import java.io.Serializable
data class TaskSetting(
val type: Int,
val type: Int, // TASK_CONDITION_FRAGMENT_LIST 索引加上 KEY_BACK_CODE_CONDITION 或者 TASK_ACTION_FRAGMENT_LIST 索引加上 KEY_BACK_CODE_ACTION
val title: String,
val description: String,
var setting: String = "",
@ -16,9 +17,10 @@ data class TaskSetting(
val iconId: Int
get() = when (type) {
TYPE_DINGTALK_GROUP_ROBOT -> R.drawable.icon_dingtalk
TYPE_EMAIL -> R.drawable.icon_email
TYPE_BARK -> R.drawable.icon_bark
else -> R.drawable.icon_sms
TASK_CONDITION_CRON -> R.drawable.auto_task_icon_cron
TASK_CONDITION_BATTERY -> R.drawable.auto_task_icon_battery
TASK_CONDITION_CHARGE -> R.drawable.auto_task_icon_charge
TASK_CONDITION_WLAN -> R.drawable.auto_task_icon_wlan
else -> R.drawable.auto_task_icon_sim
}
}

View File

@ -8,16 +8,17 @@ import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.adapter.ItemMoveCallback
import com.idormy.sms.forwarder.adapter.TaskSettingAdapter
import com.idormy.sms.forwarder.adapter.WidgetItemAdapter
import com.idormy.sms.forwarder.adapter.spinner.ActionAdapterItem
import com.idormy.sms.forwarder.adapter.spinner.ConditionAdapterItem
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.entity.Task
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.TaskViewModel
@ -46,7 +47,7 @@ import java.util.*
@Page(name = "自动任务·编辑器")
@Suppress("PrivatePropertyName", "unused", "DEPRECATION", "UNUSED_PARAMETER")
class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClickListener, CompoundButton.OnCheckedChangeListener, RecyclerViewHolder.OnItemClickListener<PageInfo> {
class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClickListener, RecyclerViewHolder.OnItemClickListener<PageInfo> {
private val TAG: String = TasksEditFragment::class.java.simpleName
private val that = this
@ -56,37 +57,26 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
BottomSheetDialog(requireContext())
}
//触发条件列表
private var conditionId = 0L
private var conditionListSelected: MutableList<Sender> = mutableListOf()
private var conditionItemMap = HashMap<Long, LinearLayout>(2)
//执行动作列表
private var actionId = 0L
private var actionListSelected: MutableList<Sender> = mutableListOf()
private var actionItemMap = HashMap<Long, LinearLayout>(2)
@JvmField
@AutoWired(name = KEY_RULE_ID)
@AutoWired(name = KEY_TASK_ID)
var taskId: Long = 0
@JvmField
@AutoWired(name = KEY_RULE_TYPE)
var taskType: String = "sms"
@AutoWired(name = KEY_TASK_TYPE)
var taskType: Int = 0
@JvmField
@AutoWired(name = KEY_RULE_CLONE)
@AutoWired(name = KEY_TASK_CLONE)
var isClone: Boolean = false
//初始化数据
private val itemListConditions = mutableListOf(
TaskSetting(TYPE_DINGTALK_GROUP_ROBOT, "Item 1", "Description 1"), TaskSetting(TYPE_EMAIL, "Item 2", "Description 2"), TaskSetting(TYPE_BARK, "Item 3", "Description 3")
// ... other items
)
private val itemListActions = mutableListOf(
TaskSetting(TYPE_DINGTALK_GROUP_ROBOT, "Apple", "Description Apple"), TaskSetting(TYPE_EMAIL, "Banana", "Description Banana"), TaskSetting(TYPE_BARK, "Orange", "Description Orange")
// ... other items
)
private lateinit var recyclerConditions: RecyclerView
private lateinit var recyclerActions: RecyclerView
private lateinit var conditionsAdapter: TaskSettingAdapter
private lateinit var actionsAdapter: TaskSettingAdapter
private var itemListConditions = mutableListOf<TaskSetting>()
private var itemListActions = mutableListOf<TaskSetting>()
override fun initArgs() {
XRouter.getInstance().inject(this)
@ -116,6 +106,50 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
binding!!.btnDel.setText(R.string.del)
initForm()
}
recyclerConditions = findViewById(R.id.recycler_conditions)
recyclerActions = findViewById(R.id.recycler_actions)
// 初始化 RecyclerView 和 Adapter
initRecyclerViews()
// 添加示例项目
// addSampleItems()
// 设置拖动排序
val conditionsCallback = ItemMoveCallback(object : ItemMoveCallback.Listener {
override fun onItemMove(fromPosition: Int, toPosition: Int) {
Log.d(TAG, "onItemMove: $fromPosition $toPosition")
conditionsAdapter.onItemMove(fromPosition, toPosition)
}
override fun onDragFinished() {
//itemListConditions保持与adapter一致
itemListConditions = conditionsAdapter.itemList.toMutableList()
Log.d(TAG, "onItemMove: $itemListConditions")
}
})
val itemTouchHelperConditions = ItemTouchHelper(conditionsCallback)
itemTouchHelperConditions.attachToRecyclerView(recyclerConditions)
conditionsAdapter.setTouchHelper(itemTouchHelperConditions)
val actionsCallback = ItemMoveCallback(object : ItemMoveCallback.Listener {
override fun onItemMove(fromPosition: Int, toPosition: Int) {
Log.d(TAG, "onItemMove: $fromPosition $toPosition")
actionsAdapter.onItemMove(fromPosition, toPosition)
}
override fun onDragFinished() {
//itemListActions保持与adapter一致
itemListActions = actionsAdapter.itemList.toMutableList()
Log.d(TAG, "onItemMove: $itemListActions")
}
})
val itemTouchHelperActions = ItemTouchHelper(actionsCallback)
itemTouchHelperActions.attachToRecyclerView(recyclerActions)
actionsAdapter.setTouchHelper(itemTouchHelperActions)
}
override fun initListeners() {
@ -126,10 +160,6 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
binding!!.btnSave.setOnClickListener(this)
}
override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {/*when (buttonView?.id) {
}*/
}
@SuppressLint("InflateParams")
@SingleClick
override fun onClick(v: View) {
@ -199,82 +229,6 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
}
}
/**
* 动态增删ConditionItem
*
* @param conditionItemMap 管理item的map用于删除指定header
* @param layoutConditions 需要挂载item的LinearLayout
* @param condition ConditionAdapterItem
*/
@SuppressLint("SetTextI18n")
private fun addConditionItemLinearLayout(
conditionItemMap: MutableMap<Long, LinearLayout>, layoutConditions: LinearLayout, condition: ConditionAdapterItem
) {
val layoutConditionItem = View.inflate(requireContext(), R.layout.item_add_condition, null) as LinearLayout
val ivRemoveCondition = layoutConditionItem.findViewById<ImageView>(R.id.iv_remove_condition)
val ivConditionImage = layoutConditionItem.findViewById<ImageView>(R.id.iv_condition_image)
val tvConditionName = layoutConditionItem.findViewById<TextView>(R.id.tv_condition_name)
ivConditionImage.setImageDrawable(condition.icon)
val conditionItemId = condition.id as Long
tvConditionName.text = "ID-$conditionItemId${condition.title}"
ivRemoveCondition.tag = conditionItemId
ivRemoveCondition.setOnClickListener { view2: View ->
val tagId = view2.tag as Long
layoutConditions.removeView(conditionItemMap[tagId])
conditionItemMap.remove(tagId)
}
layoutConditions.addView(layoutConditionItem)
conditionItemMap[conditionItemId] = layoutConditionItem
if (conditionItemMap.isNotEmpty()) {
binding!!.tvAddCondition.text = getString(R.string.add_condition_continue)
binding!!.tvAddConditionTips.visibility = View.GONE
} else {
binding!!.tvAddCondition.text = getString(R.string.add_condition)
binding!!.tvAddConditionTips.visibility = View.VISIBLE
}
}
/**
* 动态增删ActionItem
*
* @param actionItemMap 管理item的map用于删除指定header
* @param layoutActions 需要挂载item的LinearLayout
* @param action ActionAdapterItem
*/
@SuppressLint("SetTextI18n")
private fun addActionItemLinearLayout(
actionItemMap: MutableMap<Long, LinearLayout>, layoutActions: LinearLayout, action: ActionAdapterItem
) {
val layoutActionItem = View.inflate(requireContext(), R.layout.item_add_action, null) as LinearLayout
val ivRemoveAction = layoutActionItem.findViewById<ImageView>(R.id.iv_remove_action)
val ivActionImage = layoutActionItem.findViewById<ImageView>(R.id.iv_action_image)
val tvActionName = layoutActionItem.findViewById<TextView>(R.id.tv_action_name)
ivActionImage.setImageDrawable(action.icon)
val actionItemId = action.id as Long
tvActionName.text = "ID-$actionItemId${action.title}"
ivRemoveAction.tag = actionItemId
ivRemoveAction.setOnClickListener { view2: View ->
val tagId = view2.tag as Long
layoutActions.removeView(actionItemMap[tagId])
actionItemMap.remove(tagId)
}
layoutActions.addView(layoutActionItem)
actionItemMap[actionItemId] = layoutActionItem
if (actionItemMap.isNotEmpty()) {
binding!!.tvAddAction.text = getString(R.string.add_action_continue)
binding!!.tvAddActionTips.visibility = View.GONE
} else {
binding!!.tvAddAction.text = getString(R.string.add_action)
binding!!.tvAddActionTips.visibility = View.VISIBLE
}
}
//初始化表单
private fun initForm() {
AppDatabase.getInstance(requireContext()).taskDao().get(taskId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Task> {
@ -300,18 +254,10 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
//提交前检查表单
private fun checkForm(): Task {
if (conditionListSelected.isEmpty() || conditionId == 0L) {
throw Exception(getString(R.string.new_sender_first))
}
if (actionListSelected.isEmpty() || actionId == 0L) {
throw Exception(getString(R.string.new_sender_first))
}
return Task()
}
private fun testTask(task: Task) {
}
@SingleClick
@ -319,8 +265,28 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
try {
dialog.dismiss()
Log.d(TAG, "onItemClick: $widgetInfo")
//判断点击的是条件还是动作
if (widgetInfo.classPath.contains(".condition.")) {
//判断是否已经添加过该类型条件
for (item in itemListConditions) {
//注意TASK_CONDITION_XXX 枚举值 等于 TASK_CONDITION_FRAGMENT_LIST 索引加上 KEY_BACK_CODE_CONDITION不可改变
if (item.type == pos + KEY_BACK_CODE_CONDITION) {
XToastUtils.error("已经添加过该类型条件")
return
}
}
} else {
//判断是否已经添加过该类型动作
for (item in itemListActions) {
//注意TASK_ACTION_XXX 枚举值 等于 TASK_ACTION_FRAGMENT_LIST 索引加上 KEY_BACK_CODE_ACTION不可改变
if (item.type == pos + KEY_BACK_CODE_ACTION) {
XToastUtils.error("已经添加过该类型动作")
return
}
}
}
@Suppress("UNCHECKED_CAST") PageOption.to(Class.forName(widgetInfo.classPath) as Class<XPageFragment>) //跳转的fragment
.setRequestCode(pos) //请求码,用于返回结果
.setRequestCode(0) //requestCode: 0 新增 、>0 编辑itemListXxx 的索引加1
.open(this)
} catch (e: Exception) {
e.printStackTrace()
@ -328,25 +294,127 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
}
}
@SuppressLint("NotifyDataSetChanged")
override fun onFragmentResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onFragmentResult(requestCode, resultCode, data)
Log.d(TAG, "requestCode:$requestCode resultCode:$resultCode data:$data")
if (data != null) {
val extras = data.extras
var backData: String? = null
if (resultCode == KEY_BACK_CODE_CONDITION) {
backData = extras!!.getString(KEY_BACK_DATA_CONDITION)
if (backData == null) return
when (requestCode) {
0 -> {
val settingVo = Gson().fromJson(backData, CronSetting::class.java)
val condition = ConditionAdapterItem(settingVo.expression) //TODO: 构建列表项目
addConditionItemLinearLayout(conditionItemMap, binding!!.layoutConditions, condition)
var setting: String? = null
if (resultCode in KEY_BACK_CODE_CONDITION..KEY_BACK_CODE_CONDITION + 999) {
setting = extras!!.getString(KEY_BACK_DATA_CONDITION)
if (setting == null) return
//注意TASK_CONDITION_XXX 枚举值 等于 TASK_CONDITION_FRAGMENT_LIST 索引加上 KEY_BACK_CODE_CONDITION不可改变
val widgetInfoIndex = resultCode - KEY_BACK_CODE_CONDITION
if (widgetInfoIndex >= TASK_CONDITION_FRAGMENT_LIST.size) return
val widgetInfo = TASK_CONDITION_FRAGMENT_LIST[widgetInfoIndex]
val taskSetting: TaskSetting
when (resultCode) {
TASK_CONDITION_CRON -> {
val settingVo = Gson().fromJson(setting, CronSetting::class.java)
Log.d(TAG, settingVo.toString())
taskSetting = TaskSetting(
resultCode, widgetInfo.name, settingVo.description, setting, requestCode
)
}
TASK_CONDITION_BATTERY -> {
val settingVo = Gson().fromJson(setting, CronSetting::class.java)
Log.d(TAG, settingVo.toString())
taskSetting = TaskSetting(
resultCode, widgetInfo.name, settingVo.description, setting, requestCode
)
}
else -> {
return
}
}
//requestCode: 等于 itemListConditions 的索引加1
if (requestCode == 0) {
taskSetting.position = itemListConditions.size
itemListConditions.add(taskSetting)
} else {
itemListConditions[requestCode - 1] = taskSetting
}
conditionsAdapter.notifyDataSetChanged()
} else if (resultCode == KEY_BACK_CODE_ACTION) {
backData = extras!!.getString(KEY_BACK_DATA_ACTION)
setting = extras!!.getString(KEY_BACK_DATA_ACTION)
}
Log.d(TAG, "requestCode:$requestCode resultCode:$resultCode backData:$backData")
Log.d(TAG, "requestCode:$requestCode resultCode:$resultCode setting:$setting")
}
}
@SuppressLint("NotifyDataSetChanged")
private fun addSampleItems() {
// 添加示例项目到列表中
itemListConditions.add(TaskSetting(TYPE_DINGTALK_GROUP_ROBOT, "DingTalk 1", "Description 1"))
itemListConditions.add(TaskSetting(TYPE_DINGTALK_GROUP_ROBOT, "DingTalk 2", "Description 2"))
itemListConditions.add(TaskSetting(TYPE_DINGTALK_GROUP_ROBOT, "DingTalk 3", "Description 3"))
itemListActions.add(TaskSetting(TYPE_EMAIL, "Email 1", "Description 1"))
itemListActions.add(TaskSetting(TYPE_EMAIL, "Email 2", "Description 2"))
itemListActions.add(TaskSetting(TYPE_EMAIL, "Email 3", "Description 3"))
// 更新 Adapter
conditionsAdapter.notifyDataSetChanged()
actionsAdapter.notifyDataSetChanged()
}
private fun initRecyclerViews() {
conditionsAdapter = TaskSettingAdapter(itemListConditions, { position -> editCondition(position) }, { position -> removeCondition(position) })
actionsAdapter = TaskSettingAdapter(itemListActions, { position -> editAction(position) }, { position -> removeAction(position) })
recyclerConditions.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = conditionsAdapter
}
recyclerActions.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = actionsAdapter
}
}
private fun editCondition(position: Int) {
// 实现编辑条件项目的逻辑
// 根据 position 对特定项目进行编辑
val condition = itemListConditions[position]
Log.d(TAG, "editCondition: $position, $condition")
val widgetInfoIndex = condition.type - KEY_BACK_CODE_CONDITION
//判断是否存在
if (widgetInfoIndex < 0 || widgetInfoIndex >= TASK_CONDITION_FRAGMENT_LIST.size) return
val widgetInfo = TASK_CONDITION_FRAGMENT_LIST[condition.type - KEY_BACK_CODE_CONDITION]
@Suppress("UNCHECKED_CAST") PageOption.to(Class.forName(widgetInfo.classPath) as Class<XPageFragment>) //跳转的fragment
.setRequestCode(position + 1) //requestCode: 0 新增 、>0 编辑itemListConditions 的索引加1
.putString(KEY_EVENT_DATA_CONDITION, condition.setting)
.open(this)
}
private fun removeCondition(position: Int) {
itemListConditions.removeAt(position)
conditionsAdapter.notifyItemRemoved(position)
}
private fun editAction(position: Int) {
// 实现编辑操作项目的逻辑
// 根据 position 对特定项目进行编辑
val action = itemListActions[position]
Log.d(TAG, "editAction: $position, $action")
val widgetInfoIndex = action.type - KEY_BACK_CODE_ACTION
//判断是否存在
if (widgetInfoIndex < 0 || widgetInfoIndex >= TASK_ACTION_FRAGMENT_LIST.size) return
val widgetInfo = TASK_ACTION_FRAGMENT_LIST[action.type - KEY_BACK_CODE_ACTION]
@Suppress("UNCHECKED_CAST") PageOption.to(Class.forName(widgetInfo.classPath) as Class<XPageFragment>) //跳转的fragment
.setRequestCode(position + 1) //requestCode: 0 新增 、>0 编辑itemListActions 的索引加1
.putString(KEY_EVENT_DATA_ACTION, action.setting)
.open(this)
}
private fun removeAction(position: Int) {
itemListActions.removeAt(position)
actionsAdapter.notifyItemRemoved(position)
}
}

View File

@ -15,10 +15,10 @@ 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.utils.KEY_BACK_CODE_CONDITION
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_CONDITION
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_CONDITION
import com.idormy.sms.forwarder.utils.KEY_TEST_CONDITION
import com.idormy.sms.forwarder.utils.TASK_CONDITION_CRON
import com.idormy.sms.forwarder.utils.XToastUtils
import com.jeremyliao.liveeventbus.LiveEventBus
import com.xuexiang.xaop.annotation.SingleClick
@ -203,7 +203,7 @@ class CronFragment : BaseFragment<FragmentTasksCronBinding?>(), View.OnClickList
val settingVo = checkSetting()
val intent = Intent()
intent.putExtra(KEY_BACK_DATA_CONDITION, Gson().toJson(settingVo))
setFragmentResult(KEY_BACK_CODE_CONDITION, intent)
setFragmentResult(TASK_CONDITION_CRON, intent)
popToBack()
return
}

View File

@ -476,6 +476,10 @@ var CLIENT_FRAGMENT_LIST = listOf(
)
//自动任务
const val KEY_TASK_ID = "key_task_id"
const val KEY_TASK_TYPE = "key_task_type"
const val KEY_TASK_CLONE = "key_task_clone"
const val KEY_TEST_CONDITION = "key_test_condition"
const val KEY_EVENT_DATA_CONDITION = "event_data_condition"
const val KEY_BACK_CODE_CONDITION = 1000
@ -486,14 +490,18 @@ const val KEY_EVENT_DATA_ACTION = "event_data_action"
const val KEY_BACK_CODE_ACTION = 2000
const val KEY_BACK_DATA_ACTION = "back_data_action"
const val TASK_CRON = 0
//注意TASK_CONDITION_XXX 枚举值 等于 TASK_CONDITION_FRAGMENT_LIST 索引加上 KEY_BACK_CODE_CONDITION不可改变
const val TASK_CONDITION_CRON = 1000
const val TASK_CONDITION_BATTERY = 1001
const val TASK_CONDITION_CHARGE = 1002
const val TASK_CONDITION_WLAN = 1003
var TASK_CONDITION_FRAGMENT_LIST = listOf(
PageInfo(
getString(R.string.task_cron),
"com.idormy.sms.forwarder.fragment.condition.CronFragment",
"{\"\":\"\"}",
CoreAnim.slide,
R.drawable.auto_task_icon_cron
R.drawable.auto_task_icon_cron,
),
PageInfo(
getString(R.string.email),
@ -517,6 +525,8 @@ var TASK_CONDITION_FRAGMENT_LIST = listOf(
R.drawable.auto_task_icon_wlan
),
)
//注意TASK_ACTION_XXX 枚举值 等于 TASK_ACTION_FRAGMENT_LIST 索引加上 KEY_BACK_CODE_ACTION不可改变
var TASK_ACTION_FRAGMENT_LIST = listOf(
PageInfo(
getString(R.string.task_cron),

View File

@ -6,15 +6,15 @@
android:layout_height="wrap_content"
android:background="@color/xui_config_color_white"
android:orientation="vertical"
android:paddingStart="5dp"
android:paddingEnd="5dp"
tools:ignore="UseCompoundDrawables">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
android:orientation="horizontal"
android:paddingTop="@dimen/config_padding_5dp"
android:paddingBottom="@dimen/config_padding_5dp">
<ImageView
android:id="@+id/iv_icon"
@ -35,7 +35,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_action"
android:textSize="18sp"
android:textSize="14sp"
android:textStyle="bold" />
<TextView

View File

@ -97,7 +97,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
android:orientation="horizontal"
android:paddingTop="@dimen/config_padding_5dp"
android:paddingBottom="@dimen/config_padding_5dp">
<ImageView
android:layout_width="36dp"
@ -118,7 +120,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_condition"
android:textSize="18sp"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
@ -180,7 +182,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
android:orientation="horizontal"
android:paddingTop="@dimen/config_padding_5dp"
android:paddingBottom="@dimen/config_padding_5dp">
<ImageView
android:layout_width="36dp"
@ -201,7 +205,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_action"
android:textSize="18sp"
android:textSize="14sp"
android:textStyle="bold" />
<TextView

View File

@ -1,68 +0,0 @@
<?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="@color/xui_config_color_white"
android:orientation="vertical"
android:paddingStart="5dp"
android:paddingEnd="5dp"
tools:ignore="UseCompoundDrawables">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_action_image"
android:layout_width="36dp"
android:layout_height="36dp"
android:src="@drawable/ic_add"
app:tint="@color/gray_text_light"
tools:ignore="ContentDescription,ImageContrastCheck" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_action_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_action"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_action_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_action_tips"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:id="@+id/iv_remove_action"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/icon_delete"
app:tint="@color/gray_text_light"
tools:ignore="ContentDescription,ImageContrastCheck" />
</LinearLayout>
<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" />
</LinearLayout>

View File

@ -1,68 +0,0 @@
<?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="@color/xui_config_color_white"
android:orientation="vertical"
android:paddingStart="5dp"
android:paddingEnd="5dp"
tools:ignore="UseCompoundDrawables">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_condition_image"
android:layout_width="36dp"
android:layout_height="36dp"
android:src="@drawable/ic_add"
app:tint="@color/gray_text_light"
tools:ignore="ContentDescription,ImageContrastCheck" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_condition_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_condition"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_condition_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_condition_tips"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:id="@+id/iv_remove_condition"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/icon_delete"
app:tint="@color/gray_text_light"
tools:ignore="ContentDescription,ImageContrastCheck" />
</LinearLayout>
<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" />
</LinearLayout>

View File

@ -58,6 +58,6 @@
<dimen name="config_padding_20dp">20dp</dimen>
<dimen name="config_padding_24dp">24dp</dimen>
<dimen name="config_padding_30dp">30dp</dimen>
<dimen name="card_view_image_size">36dp</dimen>
<dimen name="card_view_image_padding">8dp</dimen>
<dimen name="card_view_image_size">32dp</dimen>
<dimen name="card_view_image_padding">4dp</dimen>
</resources>