From 1d1fb747fc939c7c5c12ade539e594f567f8159d Mon Sep 17 00:00:00 2001 From: pppscn <35696959@qq.com> Date: Sun, 3 Dec 2023 22:55:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=C2=B7=E5=BF=AB=E6=8D=B7=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 18 +- .../sms/forwarder/activity/TaskActivity.kt | 14 + .../forwarder/adapter/TaskSettingAdapter.kt | 132 +++++++ .../adapter/spinner/ActionAdapterItem.kt | 92 ----- .../adapter/spinner/ConditionAdapterItem.kt | 92 ----- .../sms/forwarder/entity/task/TaskSetting.kt | 18 +- .../forwarder/fragment/TasksEditFragment.kt | 322 +++++++++++------- .../fragment/condition/CronFragment.kt | 4 +- .../idormy/sms/forwarder/utils/Constants.kt | 14 +- .../res/layout/adapter_task_setting_item.xml | 8 +- .../main/res/layout/fragment_tasks_edit.xml | 12 +- app/src/main/res/layout/item_add_action.xml | 68 ---- .../main/res/layout/item_add_condition.xml | 68 ---- app/src/main/res/values/dimens.xml | 4 +- 14 files changed, 393 insertions(+), 473 deletions(-) create mode 100644 app/src/main/java/com/idormy/sms/forwarder/activity/TaskActivity.kt create mode 100644 app/src/main/java/com/idormy/sms/forwarder/adapter/TaskSettingAdapter.kt delete mode 100644 app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/ActionAdapterItem.kt delete mode 100644 app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/ConditionAdapterItem.kt delete mode 100644 app/src/main/res/layout/item_add_action.xml delete mode 100644 app/src/main/res/layout/item_add_condition.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3a26f9ff..ebc18951 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -62,11 +62,12 @@ - - - - + + + + + @@ -280,6 +289,7 @@ + \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/activity/TaskActivity.kt b/app/src/main/java/com/idormy/sms/forwarder/activity/TaskActivity.kt new file mode 100644 index 00000000..b0fad2b6 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/activity/TaskActivity.kt @@ -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() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + openPage(TasksEditFragment::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/TaskSettingAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/TaskSettingAdapter.kt new file mode 100644 index 00000000..0f7a93f0 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/TaskSettingAdapter.kt @@ -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, + private val editClickListener: (Int) -> Unit, + private val removeClickListener: (Int) -> Unit +) : RecyclerView.Adapter(), 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() + } + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/ActionAdapterItem.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/ActionAdapterItem.kt deleted file mode 100644 index c3fd14b5..00000000 --- a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/ActionAdapterItem.kt +++ /dev/null @@ -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): Array { - val array = arrayOfNulls(title.size) - for (i in array.indices) { - array[i] = ActionAdapterItem(title[i]) - } - return array - } - } -} diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/ConditionAdapterItem.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/ConditionAdapterItem.kt deleted file mode 100644 index 5bb30eb2..00000000 --- a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/ConditionAdapterItem.kt +++ /dev/null @@ -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): Array { - val array = arrayOfNulls(title.size) - for (i in array.indices) { - array[i] = ConditionAdapterItem(title[i]) - } - return array - } - } -} diff --git a/app/src/main/java/com/idormy/sms/forwarder/entity/task/TaskSetting.kt b/app/src/main/java/com/idormy/sms/forwarder/entity/task/TaskSetting.kt index 8266861d..c26a66dc 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/entity/task/TaskSetting.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/entity/task/TaskSetting.kt @@ -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 } } diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/TasksEditFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/TasksEditFragment.kt index 930beda4..d9938333 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/TasksEditFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/TasksEditFragment.kt @@ -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(), View.OnClickListener, CompoundButton.OnCheckedChangeListener, RecyclerViewHolder.OnItemClickListener { +class TasksEditFragment : BaseFragment(), View.OnClickListener, RecyclerViewHolder.OnItemClickListener { private val TAG: String = TasksEditFragment::class.java.simpleName private val that = this @@ -56,37 +57,26 @@ class TasksEditFragment : BaseFragment(), View.OnClic BottomSheetDialog(requireContext()) } - //触发条件列表 - private var conditionId = 0L - private var conditionListSelected: MutableList = mutableListOf() - private var conditionItemMap = HashMap(2) - - //执行动作列表 - private var actionId = 0L - private var actionListSelected: MutableList = mutableListOf() - private var actionItemMap = HashMap(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() + private var itemListActions = mutableListOf() override fun initArgs() { XRouter.getInstance().inject(this) @@ -116,6 +106,50 @@ class TasksEditFragment : BaseFragment(), 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(), 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(), View.OnClic } } - /** - * 动态增删ConditionItem - * - * @param conditionItemMap 管理item的map,用于删除指定header - * @param layoutConditions 需要挂载item的LinearLayout - * @param condition ConditionAdapterItem - */ - @SuppressLint("SetTextI18n") - private fun addConditionItemLinearLayout( - conditionItemMap: MutableMap, layoutConditions: LinearLayout, condition: ConditionAdapterItem - ) { - val layoutConditionItem = View.inflate(requireContext(), R.layout.item_add_condition, null) as LinearLayout - val ivRemoveCondition = layoutConditionItem.findViewById(R.id.iv_remove_condition) - val ivConditionImage = layoutConditionItem.findViewById(R.id.iv_condition_image) - val tvConditionName = layoutConditionItem.findViewById(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, layoutActions: LinearLayout, action: ActionAdapterItem - ) { - val layoutActionItem = View.inflate(requireContext(), R.layout.item_add_action, null) as LinearLayout - val ivRemoveAction = layoutActionItem.findViewById(R.id.iv_remove_action) - val ivActionImage = layoutActionItem.findViewById(R.id.iv_action_image) - val tvActionName = layoutActionItem.findViewById(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 { @@ -300,18 +254,10 @@ class TasksEditFragment : BaseFragment(), 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(), 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) //跳转的fragment - .setRequestCode(pos) //请求码,用于返回结果 + .setRequestCode(0) //requestCode: 0 新增 、>0 编辑(itemListXxx 的索引加1) .open(this) } catch (e: Exception) { e.printStackTrace() @@ -328,25 +294,127 @@ class TasksEditFragment : BaseFragment(), 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) //跳转的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) //跳转的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) + } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/condition/CronFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/condition/CronFragment.kt index eaa7ba0e..1abcfdae 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/condition/CronFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/condition/CronFragment.kt @@ -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(), 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 } diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt index 81d7f46e..b2a1e956 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt @@ -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), diff --git a/app/src/main/res/layout/adapter_task_setting_item.xml b/app/src/main/res/layout/adapter_task_setting_item.xml index 736e1de7..5c7d5ff1 100644 --- a/app/src/main/res/layout/adapter_task_setting_item.xml +++ b/app/src/main/res/layout/adapter_task_setting_item.xml @@ -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"> + android:orientation="horizontal" + android:paddingTop="@dimen/config_padding_5dp" + android:paddingBottom="@dimen/config_padding_5dp"> + android:orientation="horizontal" + android:paddingTop="@dimen/config_padding_5dp" + android:paddingBottom="@dimen/config_padding_5dp"> + android:orientation="horizontal" + android:paddingTop="@dimen/config_padding_5dp" + android:paddingBottom="@dimen/config_padding_5dp"> - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_add_condition.xml b/app/src/main/res/layout/item_add_condition.xml deleted file mode 100644 index c08f5f60..00000000 --- a/app/src/main/res/layout/item_add_condition.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 2fca673c..efa00ede 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -58,6 +58,6 @@ 20dp 24dp 30dp - 36dp - 8dp + 32dp + 4dp \ No newline at end of file