From 038ab21f349ea34659a3d9cfdde0617dc4d1389e Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Fri, 8 Mar 2019 12:12:41 +0100 Subject: [PATCH] Add swipe to delete for DataListFragment --- .../android/ui/fragment/DataListFragment.kt | 80 ++++++++++--------- .../ui/helpers/SwipeToDeleteCallback.kt | 68 ++++++++++++++++ .../main/res/layout/fragment_data_list.xml | 17 ++-- .../res/layout/layout_swipe_to_delete.xml | 31 +++++++ app/src/main/res/layout/row_title.xml | 66 ++++++++------- 5 files changed, 187 insertions(+), 75 deletions(-) create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/helpers/SwipeToDeleteCallback.kt create mode 100644 app/src/main/res/layout/layout_swipe_to_delete.xml diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt index 493dd941..e0bc7ee8 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt @@ -4,11 +4,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.view.isVisible import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.snackbar.Snackbar import io.realm.Realm +import io.realm.RealmObject import io.realm.RealmResults import kotlinx.android.synthetic.main.fragment_data_list.* import net.pokeranalytics.android.R @@ -19,17 +19,20 @@ import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment +import net.pokeranalytics.android.ui.helpers.SwipeToDeleteCallback import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow -import timber.log.Timber class DataListFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource, RowRepresentableDelegate { - lateinit var dataType: SettingRow - + private lateinit var dataType: SettingRow private lateinit var items: RealmResults<*> + private lateinit var dataListAdapter: RowRepresentableAdapter + + private var deletedItem: RealmObject? = null + private var lastDeletedItemPosition: Int = 0 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_data_list, container, false) @@ -37,14 +40,12 @@ class DataListFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSourc override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initData() initUI() } override fun onResume() { super.onResume() this.recyclerView?.adapter?.notifyDataSetChanged() - noDataFound.isVisible = items.isEmpty() } override fun rowRepresentableForPosition(position: Int): RowRepresentable? { @@ -68,15 +69,11 @@ class DataListFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSourc EditableDataActivity.newInstance( requireContext(), it.ordinal, - (this.items[position] as Savable).uniqueIdentifier() + (row as Savable).uniqueIdentifier() ) } } - - private fun initData() { - } - /** * Init UI */ @@ -91,40 +88,32 @@ class DataListFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSourc activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) setHasOptionsMenu(true) - // Swipe to delete, work in progress - val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() { - - override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { + val viewManager = LinearLayoutManager(requireContext()) + dataListAdapter = RowRepresentableAdapter(this, this) - return makeFlag( - ItemTouchHelper.ACTION_STATE_SWIPE, ItemTouchHelper.START or ItemTouchHelper.END - ) - } + val swipeToDelete = SwipeToDeleteCallback(dataListAdapter) { position -> - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - return false - } + // Save the delete position & create a copy of the object + val mRecentlyDeletedItem = rowRepresentableForPosition(position) + lastDeletedItemPosition = position - override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { - super.clearView(recyclerView, viewHolder) + if (mRecentlyDeletedItem is RealmObject) { + deletedItem = getRealm().copyFromRealm(mRecentlyDeletedItem) + getRealm().executeTransaction { + mRecentlyDeletedItem.deleteFromRealm() + } + dataListAdapter.notifyItemRemoved(position) + showUndoSnackBar() } + } - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - } - }) - - val viewManager = LinearLayoutManager(requireContext()) - val dataListAdapter = RowRepresentableAdapter(this, this) + val itemTouchHelper = ItemTouchHelper(swipeToDelete) recyclerView.apply { setHasFixedSize(true) layoutManager = viewManager adapter = dataListAdapter - //itemTouchHelper.attachToRecyclerView(this) + itemTouchHelper.attachToRecyclerView(this) } this.addButton.setOnClickListener { @@ -136,7 +125,23 @@ class DataListFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSourc ) } } + } + /** + * Show undo snack bar + */ + private fun showUndoSnackBar() { + val message = String.format(getString(R.string.data_deleted), this.dataType.localizedTitle(requireContext())) + val snackBar = Snackbar.make(constraintLayout, message, Snackbar.LENGTH_LONG) + snackBar.setAction(R.string.cancel) { + getRealm().executeTransaction {realm -> + deletedItem?.let { + realm.copyToRealm(it) + dataListAdapter.notifyItemInserted(lastDeletedItemPosition) + } + } + } + snackBar.show() } /** @@ -144,13 +149,10 @@ class DataListFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSourc */ fun setData(dataType: Int) { this.dataType = SettingRow.values()[dataType] - this.toolbar.title = this.dataType.localizedTitle(requireContext()) val realm = Realm.getDefaultInstance() - this.dataType.relatedResultsRepresentable?.let { this.items = it.items(realm) - noDataFound.isVisible = this.items.isEmpty() } } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/helpers/SwipeToDeleteCallback.kt b/app/src/main/java/net/pokeranalytics/android/ui/helpers/SwipeToDeleteCallback.kt new file mode 100644 index 00000000..510242f6 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/helpers/SwipeToDeleteCallback.kt @@ -0,0 +1,68 @@ +package net.pokeranalytics.android.ui.helpers + +import android.graphics.Canvas +import android.view.View +import androidx.core.view.isVisible +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter + +/** + * Swipe to delete callback + */ +class SwipeToDeleteCallback(var adapter: RowRepresentableAdapter, var onDelete: ((position: Int) -> Unit)? = null) : + ItemTouchHelper.SimpleCallback(ItemTouchHelper.ACTION_STATE_IDLE, ItemTouchHelper.START or ItemTouchHelper.END) { + + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { + return false + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.adapterPosition + onDelete?.invoke(position) + } + + override fun onChildDraw( + c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, + dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean + ) { + val foregroundView = viewHolder.itemView.findViewById(net.pokeranalytics.android.R.id.foreground) + val backgroundView = viewHolder.itemView.findViewById(net.pokeranalytics.android.R.id.background) + foregroundView?.let { + getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY, actionState, isCurrentlyActive) + backgroundView?.findViewById(R.id.leftIcon)?.isVisible = dX > 0 + backgroundView?.findViewById(R.id.rightIcon)?.isVisible = dX < 0 + } + } + + + override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { + val foregroundView = viewHolder.itemView.findViewById(net.pokeranalytics.android.R.id.foreground) + foregroundView?.let { + getDefaultUIUtil().clearView(foregroundView) + } + } + + override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { + viewHolder?.let { + val foregroundView = viewHolder.itemView.findViewById(net.pokeranalytics.android.R.id.foreground) + foregroundView?.let { + getDefaultUIUtil().onSelected(foregroundView) + } + } + } + + override fun onChildDrawOver( + c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder?, dX: Float, dY: Float, + actionState: Int, isCurrentlyActive: Boolean + ) { + viewHolder?.let { + val foregroundView = viewHolder.itemView.findViewById(net.pokeranalytics.android.R.id.foreground) + foregroundView?.let { + getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY, actionState, isCurrentlyActive) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_data_list.xml b/app/src/main/res/layout/fragment_data_list.xml index 76c02022..f284300d 100644 --- a/app/src/main/res/layout/fragment_data_list.xml +++ b/app/src/main/res/layout/fragment_data_list.xml @@ -1,10 +1,10 @@ + android:layout_height="match_parent"> + app:layout_constraintTop_toTopOf="parent" + tools:listitem="@layout/row_title" /> + app:layout_constraintVertical_bias="0.3" + tools:visibility="visible" /> @@ -91,6 +91,7 @@ android:layout_marginEnd="16dp" android:layout_marginBottom="16dp" android:src="@drawable/ic_add" + android:tint="@color/black" app:fabSize="normal" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> diff --git a/app/src/main/res/layout/layout_swipe_to_delete.xml b/app/src/main/res/layout/layout_swipe_to_delete.xml new file mode 100644 index 00000000..71c0068b --- /dev/null +++ b/app/src/main/res/layout/layout_swipe_to_delete.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/row_title.xml b/app/src/main/res/layout/row_title.xml index 84d4ebb4..560b2c19 100644 --- a/app/src/main/res/layout/row_title.xml +++ b/app/src/main/res/layout/row_title.xml @@ -1,37 +1,47 @@ - + android:layout_height="48dp"> - + - + - + - \ No newline at end of file + + + + + + +