allow sorting of automation tasks
This commit is contained in:
parent
a33b90478b
commit
a66b3f7090
|
@ -5,10 +5,14 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.OnStartDragListener
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.SimpleItemTouchHelperCallback
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
|
@ -17,11 +21,14 @@ import io.reactivex.android.schedulers.AndroidSchedulers
|
|||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.android.synthetic.main.automation_fragment.*
|
||||
|
||||
class AutomationFragment : Fragment() {
|
||||
|
||||
class AutomationFragment : Fragment(), OnStartDragListener {
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
private var eventListAdapter: EventListAdapter? = null
|
||||
|
||||
private var itemTouchHelper: ItemTouchHelper? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.automation_fragment, container, false)
|
||||
}
|
||||
|
@ -29,7 +36,7 @@ class AutomationFragment : Fragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
eventListAdapter = EventListAdapter(AutomationPlugin.automationEvents, fragmentManager, activity)
|
||||
eventListAdapter = EventListAdapter(AutomationPlugin.automationEvents, fragmentManager, activity, this)
|
||||
automation_eventListView.layoutManager = LinearLayoutManager(context)
|
||||
automation_eventListView.adapter = eventListAdapter
|
||||
|
||||
|
@ -42,6 +49,10 @@ class AutomationFragment : Fragment() {
|
|||
fragmentManager?.let { dialog.show(it, "EditEventDialog") }
|
||||
}
|
||||
|
||||
val callback: ItemTouchHelper.Callback = SimpleItemTouchHelperCallback(eventListAdapter!!)
|
||||
itemTouchHelper = ItemTouchHelper(callback)
|
||||
itemTouchHelper?.attachToRecyclerView(automation_eventListView)
|
||||
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -81,4 +92,8 @@ class AutomationFragment : Fragment() {
|
|||
automation_logView?.text = sb.toString()
|
||||
}
|
||||
|
||||
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
|
||||
itemTouchHelper?.startDrag(viewHolder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
|
@ -17,6 +20,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -25,19 +29,26 @@ import info.nightscout.androidaps.R;
|
|||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action;
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog;
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter;
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperViewHolder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.OnStartDragListener;
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged;
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
||||
import info.nightscout.androidaps.utils.OKDialog;
|
||||
|
||||
class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder> {
|
||||
class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder> implements ItemTouchHelperAdapter {
|
||||
private final List<AutomationEvent> eventList;
|
||||
private final FragmentManager fragmentManager;
|
||||
private final Activity activity;
|
||||
|
||||
EventListAdapter(List<AutomationEvent> events, FragmentManager fragmentManager, Activity activity) {
|
||||
private final OnStartDragListener mDragStartListener;
|
||||
|
||||
EventListAdapter(List<AutomationEvent> events, FragmentManager fragmentManager, Activity activity, OnStartDragListener dragStartListener) {
|
||||
this.eventList = events;
|
||||
this.fragmentManager = fragmentManager;
|
||||
this.activity = activity;
|
||||
mDragStartListener = dragStartListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -54,6 +65,7 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
|
|||
layout.addView(iv);
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
final AutomationEvent event = eventList.get(position);
|
||||
|
@ -91,16 +103,10 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
|
|||
RxBus.INSTANCE.send(new EventAutomationDataChanged());
|
||||
});
|
||||
|
||||
// remove event
|
||||
holder.iconTrash.setOnClickListener(v ->
|
||||
OKDialog.showConfirmation(activity, MainApp.gs(R.string.removerecord) + " " + event.getTitle(), () -> {
|
||||
eventList.remove(event);
|
||||
RxBus.INSTANCE.send(new EventAutomationDataChanged());
|
||||
})
|
||||
);
|
||||
|
||||
// edit event
|
||||
holder.rootLayout.setOnClickListener(v -> {
|
||||
holder.rootLayout.setOnClickListener(v ->
|
||||
|
||||
{
|
||||
//EditEventDialog dialog = EditEventDialog.Companion.newInstance(event, false);
|
||||
EditEventDialog dialog = new EditEventDialog();
|
||||
Bundle args = new Bundle();
|
||||
|
@ -110,6 +116,17 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
|
|||
if (fragmentManager != null)
|
||||
dialog.show(fragmentManager, "EditEventDialog");
|
||||
});
|
||||
|
||||
// Start a drag whenever the handle view it touched
|
||||
holder.iconSort.setOnTouchListener((v, motionEvent) ->
|
||||
|
||||
{
|
||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mDragStartListener.onStartDrag(holder);
|
||||
return true;
|
||||
}
|
||||
return v.onTouchEvent(motionEvent);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -117,12 +134,33 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
|
|||
return eventList.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
@Override
|
||||
public boolean onItemMove(int fromPosition, int toPosition) {
|
||||
Collections.swap(eventList, fromPosition, toPosition);
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
RxBus.INSTANCE.send(new EventAutomationDataChanged());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemDismiss(int position) {
|
||||
OKDialog.showConfirmation(activity, MainApp.gs(R.string.removerecord) + " " + eventList.get(position).getTitle(),
|
||||
() -> {
|
||||
eventList.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
RxBus.INSTANCE.send(new EventAutomationDataChanged());
|
||||
RxBus.INSTANCE.send(new EventAutomationUpdateGui());
|
||||
}, () -> {
|
||||
RxBus.INSTANCE.send(new EventAutomationUpdateGui());
|
||||
});
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
|
||||
final RelativeLayout rootLayout;
|
||||
final LinearLayout iconLayout;
|
||||
final TextView eventTitle;
|
||||
final Context context;
|
||||
final ImageView iconTrash;
|
||||
final ImageView iconSort;
|
||||
final CheckBox enabled;
|
||||
|
||||
ViewHolder(View view, Context context) {
|
||||
|
@ -131,8 +169,18 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
|
|||
eventTitle = view.findViewById(R.id.viewEventTitle);
|
||||
rootLayout = view.findViewById(R.id.rootLayout);
|
||||
iconLayout = view.findViewById(R.id.iconLayout);
|
||||
iconTrash = view.findViewById(R.id.iconTrash);
|
||||
iconSort = view.findViewById(R.id.iconSort);
|
||||
enabled = view.findViewById(R.id.automation_enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected() {
|
||||
itemView.setBackgroundColor(Color.LTGRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClear() {
|
||||
itemView.setBackgroundColor(MainApp.gc(R.color.ribbonDefault));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dragHelpers
|
||||
|
||||
|
||||
interface ItemTouchHelperAdapter {
|
||||
/**
|
||||
* Called when an item has been dragged far enough to trigger a move. This is called every time
|
||||
* an item is shifted, and **not** at the end of a "drop" event.<br></br>
|
||||
* <br></br>
|
||||
* Implementations should call [RecyclerView.Adapter.notifyItemMoved] after
|
||||
* adjusting the underlying data to reflect this move.
|
||||
*
|
||||
* @param fromPosition The start position of the moved item.
|
||||
* @param toPosition Then resolved position of the moved item.
|
||||
* @return True if the item was moved to the new adapter position.
|
||||
*
|
||||
* @see RecyclerView.getAdapterPositionFor
|
||||
* @see RecyclerView.ViewHolder.getAdapterPosition
|
||||
*/
|
||||
fun onItemMove(fromPosition: Int, toPosition: Int): Boolean
|
||||
|
||||
/**
|
||||
* Called when an item has been dismissed by a swipe.<br></br>
|
||||
* <br></br>
|
||||
* Implementations should call [RecyclerView.Adapter.notifyItemRemoved] after
|
||||
* adjusting the underlying data to reflect this removal.
|
||||
*
|
||||
* @param position The position of the item dismissed.
|
||||
*
|
||||
* @see RecyclerView.getAdapterPositionFor
|
||||
* @see RecyclerView.ViewHolder.getAdapterPosition
|
||||
*/
|
||||
fun onItemDismiss(position: Int)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dragHelpers
|
||||
|
||||
/**
|
||||
* Interface to notify an item ViewHolder of relevant callbacks from [ ].
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
interface ItemTouchHelperViewHolder {
|
||||
/**
|
||||
* Called when the [ItemTouchHelper] first registers an item as being moved or swiped.
|
||||
* Implementations should update the item view to indicate it's active state.
|
||||
*/
|
||||
fun onItemSelected()
|
||||
|
||||
/**
|
||||
* Called when the [ItemTouchHelper] has completed the move or swipe, and the active item
|
||||
* state should be cleared.
|
||||
*/
|
||||
fun onItemClear()
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dragHelpers
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
interface OnStartDragListener {
|
||||
/**
|
||||
* Called when a view is requesting a start of a drag.
|
||||
*
|
||||
* @param viewHolder The holder of the view to drag.
|
||||
*/
|
||||
fun onStartDrag(viewHolder: RecyclerView.ViewHolder)
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dragHelpers
|
||||
|
||||
import android.graphics.Canvas
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of [ItemTouchHelper.Callback] that enables basic drag & drop and
|
||||
* swipe-to-dismiss. Drag events are automatically started by an item long-press.<br></br>
|
||||
*
|
||||
* Expects the `RecyclerView.Adapter` to listen for [ ] callbacks and the `RecyclerView.ViewHolder` to implement
|
||||
* [ItemTouchHelperViewHolder].
|
||||
*
|
||||
*/
|
||||
class SimpleItemTouchHelperCallback(private val mAdapter: ItemTouchHelperAdapter) : ItemTouchHelper.Callback() {
|
||||
override fun isLongPressDragEnabled(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isItemViewSwipeEnabled(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { // Set movement flags based on the layout manager
|
||||
return if (recyclerView.layoutManager is GridLayoutManager) {
|
||||
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
|
||||
val swipeFlags = 0
|
||||
makeMovementFlags(dragFlags, swipeFlags)
|
||||
} else {
|
||||
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
|
||||
val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
|
||||
makeMovementFlags(dragFlags, swipeFlags)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMove(recyclerView: RecyclerView, source: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
|
||||
if (source.itemViewType != target.itemViewType) {
|
||||
return false
|
||||
}
|
||||
// Notify the adapter of the move
|
||||
mAdapter.onItemMove(source.adapterPosition, target.adapterPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, i: Int) { // Notify the adapter of the dismissal
|
||||
mAdapter.onItemDismiss(viewHolder.adapterPosition)
|
||||
}
|
||||
|
||||
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { // Fade out the view as it is swiped out of the parent's bounds
|
||||
val alpha = ALPHA_FULL - abs(dX) / viewHolder.itemView.width.toFloat()
|
||||
viewHolder.itemView.alpha = alpha
|
||||
viewHolder.itemView.translationX = dX
|
||||
} else {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { // We only want the active item to change
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
|
||||
if (viewHolder is ItemTouchHelperViewHolder) { // Let the view holder know that this item is being moved or dragged
|
||||
val itemViewHolder: ItemTouchHelperViewHolder = viewHolder
|
||||
itemViewHolder.onItemSelected()
|
||||
}
|
||||
}
|
||||
super.onSelectedChanged(viewHolder, actionState)
|
||||
}
|
||||
|
||||
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.clearView(recyclerView, viewHolder)
|
||||
viewHolder.itemView.alpha = ALPHA_FULL
|
||||
if (viewHolder is ItemTouchHelperViewHolder) { // Tell the view holder it's time to restore the idle state
|
||||
val itemViewHolder: ItemTouchHelperViewHolder = viewHolder
|
||||
itemViewHolder.onItemClear()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ALPHA_FULL = 1.0f
|
||||
}
|
||||
|
||||
}
|
5
app/src/main/res/drawable/ic_reorder_gray_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_reorder_gray_24dp.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#C0C0C0"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M3,15h18v-2L3,13v2zM3,19h18v-2L3,17v2zM3,11h18L21,9L3,9v2zM3,5v2h18L21,5L3,5z"/>
|
||||
</vector>
|
|
@ -8,6 +8,8 @@
|
|||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="@color/ribbonDefault"
|
||||
android:padding="8dp">
|
||||
|
||||
|
@ -26,21 +28,21 @@
|
|||
android:layout_alignBottom="@+id/automation_enabled"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_toStartOf="@+id/iconTrash"
|
||||
android:layout_toStartOf="@+id/iconSort"
|
||||
android:layout_toEndOf="@id/automation_enabled"
|
||||
android:text="Title"
|
||||
android:textAlignment="viewStart"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iconTrash"
|
||||
android:id="@+id/iconSort"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:contentDescription="@string/remove_label"
|
||||
android:contentDescription="@string/reorder_label"
|
||||
android:orientation="horizontal"
|
||||
android:src="@drawable/ic_trash_outline" />
|
||||
android:src="@drawable/ic_reorder_gray_24dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/iconLayout"
|
||||
|
|
|
@ -1660,5 +1660,6 @@
|
|||
<string name="profilenamecontainsdot">Profile name contains dots.\nThis is not supported by NS.\nProfile is not uploaded to NS.</string>
|
||||
<string name="low_mark_comment">Lower value of in range area (display only)</string>
|
||||
<string name="high_mark_comment">Higher value of in range area (display only)</string>
|
||||
<string name="reorder_label">Reorder</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue