swipe to delete
This commit is contained in:
parent
9cf5133469
commit
f68d75c226
@ -14,8 +14,8 @@
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="assetSourceType" value="FILE" />
|
||||
<entry key="outputName" value="ic_pause" />
|
||||
<entry key="sourceFile" value="C:\Users\Mike\Downloads\pause-symbol.svg" />
|
||||
<entry key="outputName" value="ic_garbage" />
|
||||
<entry key="sourceFile" value="C:\Users\Mike\Downloads\garbage.svg" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
|
@ -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 ?)
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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,13 +70,29 @@ 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)
|
||||
@ -85,6 +102,8 @@ public class MessageAdapter extends RecyclerView.Adapter
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
android/app/src/main/res/drawable/ic_trash.xml
Normal file
16
android/app/src/main/res/drawable/ic_trash.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportHeight="53"
|
||||
android:viewportWidth="53"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M42.943,6H33.5V3c0,-1.654 -1.346,-3 -3,-3h-8c-1.654,0 -3,1.346 -3,3v3h-9.443C8.096,6 6.5,7.596 6.5,9.557V14h2h36h2V9.557C46.5,7.596 44.904,6 42.943,6zM31.5,6h-10V3c0,-0.552 0.449,-1 1,-1h8c0.551,0 1,0.448 1,1V6z"/>
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M8.5,49.271C8.5,51.327 10.173,53 12.229,53h28.541c2.057,0 3.729,-1.673 3.729,-3.729V16h-36V49.271z"/>
|
||||
|
||||
</vector>
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
android:id="@+id/layoutRoot"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -1,9 +1,43 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/layoutBack"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="@dimen/card_margin"
|
||||
android:background="@color/bg_row_background">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/delete_icon"
|
||||
android:layout_width="@dimen/ic_delete"
|
||||
android:layout_height="@dimen/ic_delete"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="@dimen/padd_10"
|
||||
android:src="@drawable/ic_trash"
|
||||
android:contentDescription="@string/delete" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="@dimen/padd_10"
|
||||
android:layout_toLeftOf="@id/delete_icon"
|
||||
android:text="@string/delete"
|
||||
android:textColor="#fff"
|
||||
android:textSize="13dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/layoutFront"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="match_parent"
|
||||
@ -78,4 +112,6 @@
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
</FrameLayout>
|
@ -7,4 +7,6 @@
|
||||
<color name="colorHeaderForeground">#FFFFFF</color>
|
||||
|
||||
<color name="colorBlack">#000</color>
|
||||
|
||||
<color name="bg_row_background">#fa315b</color>
|
||||
</resources>
|
||||
|
@ -2,4 +2,8 @@
|
||||
<resources>
|
||||
<dimen name="card_margin">5dp</dimen>
|
||||
<dimen name="card_album_radius">0dp</dimen>
|
||||
|
||||
<dimen name="padd_10">10dp</dimen>
|
||||
<dimen name="ic_delete">30dp</dimen>
|
||||
<dimen name="thumbnail">90dp</dimen>
|
||||
</resources>
|
@ -33,4 +33,5 @@
|
||||
<string name="str_promode_info">Increase your daily quota, remove the ad banner and support the developer (that\'s me)</string>
|
||||
<string name="volume_icon">Volume icon</string>
|
||||
<string name="play_test_sound">Play test sound</string>
|
||||
<string name="delete">DELETE</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user