From f68d75c226b5b12221aa67fd3fcb51b46011f667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Sat, 17 Nov 2018 03:09:18 +0100 Subject: [PATCH] swipe to delete --- android/.idea/assetWizardSettings.xml | 4 +- .../simplecloudnotifier/SCNApp.java | 2 +- .../model/CMessageList.java | 12 ++ .../util/MessageAdapterTouchHelper.java | 77 +++++++++ .../view/MainActivity.java | 4 + .../view/MessageAdapter.java | 29 +++- .../view/NotificationsFragment.java | 35 +++- .../app/src/main/res/drawable/ic_trash.xml | 16 ++ .../app/src/main/res/layout/activity_main.xml | 1 + .../app/src/main/res/layout/message_card.xml | 158 +++++++++++------- android/app/src/main/res/values/colors.xml | 2 + android/app/src/main/res/values/dimens.xml | 4 + android/app/src/main/res/values/strings.xml | 1 + 13 files changed, 273 insertions(+), 72 deletions(-) create mode 100644 android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/util/MessageAdapterTouchHelper.java create mode 100644 android/app/src/main/res/drawable/ic_trash.xml diff --git a/android/.idea/assetWizardSettings.xml b/android/.idea/assetWizardSettings.xml index 65911ec..28bdeb3 100644 --- a/android/.idea/assetWizardSettings.xml +++ b/android/.idea/assetWizardSettings.xml @@ -14,8 +14,8 @@ diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/SCNApp.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/SCNApp.java index 7d686ec..e66b130 100644 --- a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/SCNApp.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/SCNApp.java @@ -104,8 +104,8 @@ public class SCNApp extends Application implements LifecycleObserver [ ] - test notification channels [ ] - startup time -[ ] - Delete single message (swipe right) [ ] - periodically get non-ack (option - even when not in-app) +[ ] - expand long content on click [ ] - publish (+ HN post ?) diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/model/CMessageList.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/model/CMessageList.java index f425898..a6f5eaa 100644 --- a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/model/CMessageList.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/model/CMessageList.java @@ -169,4 +169,16 @@ public class CMessageList { return AllAcks.contains(Long.toHexString(id)); } + + public void remove(int index) + { + Messages.remove(index); + fullSave(); + } + + public void insert(int index, CMessage item) + { + Messages.add(index, item); + fullSave(); + } } diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/util/MessageAdapterTouchHelper.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/util/MessageAdapterTouchHelper.java new file mode 100644 index 0000000..191eb75 --- /dev/null +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/util/MessageAdapterTouchHelper.java @@ -0,0 +1,77 @@ +package com.blackforestbytes.simplecloudnotifier.util; + +import android.graphics.Canvas; +import android.view.View; + +import com.blackforestbytes.simplecloudnotifier.view.MessageAdapter; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.RecyclerView; + +public class MessageAdapterTouchHelper extends ItemTouchHelper.SimpleCallback +{ + private MessageAdapterTouchHelperListener listener; + + public MessageAdapterTouchHelper(int dragDirs, int swipeDirs, MessageAdapterTouchHelperListener listener) + { + super(dragDirs, swipeDirs); + this.listener = listener; + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) + { + return true; + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) + { + if (viewHolder != null) + { + final View foregroundView = ((MessageAdapter.MessagePresenter) viewHolder).viewForeground; + + getDefaultUIUtil().onSelected(foregroundView); + } + } + + @Override + public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) + { + final View foregroundView = ((MessageAdapter.MessagePresenter) viewHolder).viewForeground; + getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY, actionState, isCurrentlyActive); + } + + @Override + public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) + { + final View foregroundView = ((MessageAdapter.MessagePresenter) viewHolder).viewForeground; + getDefaultUIUtil().clearView(foregroundView); + } + + @Override + public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) + { + final View foregroundView = ((MessageAdapter.MessagePresenter) viewHolder).viewForeground; + + getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY, actionState, isCurrentlyActive); + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) + { + listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition()); + } + + @Override + public int convertToAbsoluteDirection(int flags, int layoutDirection) + { + return super.convertToAbsoluteDirection(flags, layoutDirection); + } + + public interface MessageAdapterTouchHelperListener + { + void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position); + } +} diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/MainActivity.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/MainActivity.java index 9449b31..01f61a3 100644 --- a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/MainActivity.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/MainActivity.java @@ -1,6 +1,7 @@ package com.blackforestbytes.simplecloudnotifier.view; import android.os.Bundle; +import android.widget.RelativeLayout; import com.blackforestbytes.simplecloudnotifier.R; import com.blackforestbytes.simplecloudnotifier.SCNApp; @@ -18,6 +19,7 @@ import androidx.viewpager.widget.ViewPager; public class MainActivity extends AppCompatActivity { public TabAdapter adpTabs; + public RelativeLayout layoutRoot; @Override protected void onCreate(Bundle savedInstanceState) @@ -28,6 +30,8 @@ public class MainActivity extends AppCompatActivity NotificationService.inst(); CMessageList.inst(); + layoutRoot = findViewById(R.id.layoutRoot); + Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/MessageAdapter.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/MessageAdapter.java index caee2e6..9f1128b 100644 --- a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/MessageAdapter.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/MessageAdapter.java @@ -4,6 +4,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; +import android.widget.RelativeLayout; import android.widget.TextView; import com.blackforestbytes.simplecloudnotifier.R; @@ -69,22 +70,40 @@ public class MessageAdapter extends RecyclerView.Adapter manLayout.smoothScrollToPosition(viewRecycler, null, 0); } - private class MessagePresenter extends RecyclerView.ViewHolder implements View.OnClickListener + + public void removeItem(int position) + { + CMessageList.inst().remove(position); + notifyItemRemoved(position); + } + + public void restoreItem(CMessage item, int position) + { + CMessageList.inst().insert(position, item); + notifyItemInserted(position); + } + + public class MessagePresenter extends RecyclerView.ViewHolder implements View.OnClickListener { private TextView tvTimestamp; private TextView tvTitle; private TextView tvMessage; private ImageView ivPriority; + public RelativeLayout viewForeground; + public RelativeLayout viewBackground; + private CMessage data; MessagePresenter(View itemView) { super(itemView); - tvTimestamp = itemView.findViewById(R.id.tvTimestamp); - tvTitle = itemView.findViewById(R.id.tvTitle); - tvMessage = itemView.findViewById(R.id.tvMessage); - ivPriority = itemView.findViewById(R.id.ivPriority); + tvTimestamp = itemView.findViewById(R.id.tvTimestamp); + tvTitle = itemView.findViewById(R.id.tvTitle); + tvMessage = itemView.findViewById(R.id.tvMessage); + ivPriority = itemView.findViewById(R.id.ivPriority); + viewForeground = itemView.findViewById(R.id.layoutFront); + viewBackground = itemView.findViewById(R.id.layoutBack); itemView.setOnClickListener(this); } diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/NotificationsFragment.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/NotificationsFragment.java index 6963d3b..dc39167 100644 --- a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/NotificationsFragment.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/view/NotificationsFragment.java @@ -1,24 +1,32 @@ package com.blackforestbytes.simplecloudnotifier.view; +import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.blackforestbytes.simplecloudnotifier.R; +import com.blackforestbytes.simplecloudnotifier.SCNApp; +import com.blackforestbytes.simplecloudnotifier.model.CMessage; +import com.blackforestbytes.simplecloudnotifier.model.CMessageList; import com.blackforestbytes.simplecloudnotifier.model.SCNSettings; import com.blackforestbytes.simplecloudnotifier.service.IABService; +import com.blackforestbytes.simplecloudnotifier.util.MessageAdapterTouchHelper; import com.google.android.gms.ads.doubleclick.PublisherAdRequest; import com.google.android.gms.ads.doubleclick.PublisherAdView; +import com.google.android.material.snackbar.Snackbar; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -public class NotificationsFragment extends Fragment +public class NotificationsFragment extends Fragment implements MessageAdapterTouchHelper.MessageAdapterTouchHelperListener { private PublisherAdView adView; + private MessageAdapter adpMessages; public NotificationsFragment() { @@ -33,8 +41,10 @@ public class NotificationsFragment extends Fragment RecyclerView rvMessages = v.findViewById(R.id.rvMessages); LinearLayoutManager lman = new LinearLayoutManager(this.getContext(), RecyclerView.VERTICAL, false); rvMessages.setLayoutManager(lman); - rvMessages.setAdapter(new MessageAdapter(v.findViewById(R.id.tvNoElements), lman, rvMessages)); - //lman.scrollToPosition(0); + rvMessages.setAdapter(adpMessages = new MessageAdapter(v.findViewById(R.id.tvNoElements), lman, rvMessages)); + + ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new MessageAdapterTouchHelper(0, ItemTouchHelper.LEFT, this); + new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(rvMessages); adView = v.findViewById(R.id.adBanner); PublisherAdRequest adRequest = new PublisherAdRequest.Builder().build(); @@ -49,4 +59,23 @@ public class NotificationsFragment extends Fragment { if (adView != null) adView.setVisibility(IABService.inst().getPurchaseCached(IABService.IAB_PRO_MODE) != null ? View.GONE : View.VISIBLE); } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position) + { + if (viewHolder instanceof MessageAdapter.MessagePresenter) + { + final CMessage deletedItem = CMessageList.inst().tryGet(viewHolder.getAdapterPosition()); + final int deletedIndex = viewHolder.getAdapterPosition(); + + String name = deletedItem.Title; + + adpMessages.removeItem(viewHolder.getAdapterPosition()); + + Snackbar snackbar = Snackbar.make(SCNApp.getMainActivity().layoutRoot, name + " removed", Snackbar.LENGTH_LONG); + snackbar.setAction("UNDO", view -> adpMessages.restoreItem(deletedItem, deletedIndex)); + snackbar.setActionTextColor(Color.YELLOW); + snackbar.show(); + } + } } diff --git a/android/app/src/main/res/drawable/ic_trash.xml b/android/app/src/main/res/drawable/ic_trash.xml new file mode 100644 index 0000000..e4cbad7 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_trash.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml index 8936305..40d5509 100644 --- a/android/app/src/main/res/layout/activity_main.xml +++ b/android/app/src/main/res/layout/activity_main.xml @@ -1,5 +1,6 @@ - + android:background="@color/bg_row_background"> + - + + + + + + + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_margin="@dimen/card_margin" + android:elevation="3dp" + card_view:cardCornerRadius="@dimen/card_album_radius"> - + - + android:text="2018-09-11 20:22:32" /> - + android:text="Message from me"/> - + + android:text="asdasd asdasd asdasd a" /> - + - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index b5e8acb..a996d22 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -7,4 +7,6 @@ #FFFFFF #000 + + #fa315b diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml index 62e9e2f..939fe4d 100644 --- a/android/app/src/main/res/values/dimens.xml +++ b/android/app/src/main/res/values/dimens.xml @@ -2,4 +2,8 @@ 5dp 0dp + + 10dp + 30dp + 90dp \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 12ef74c..8cd8a68 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -33,4 +33,5 @@ Increase your daily quota, remove the ad banner and support the developer (that\'s me) Volume icon Play test sound + DELETE