OneUIProject / oneui-core

Samsung's One UI core libraries for Android apps.
MIT License
122 stars 15 forks source link

Trying to implement SelectMode on ToolbarLayout #10

Closed veso266 closed 2 years ago

veso266 commented 2 years ago

Hello there, I am trying to implement multiSelect on RecycleView on ToolbarLayout, just like in this picture multi-select

But I am failing

My selecting methods look like this

public void setSelecting(boolean enabled) {
        TabLayout subTabs = getActivity().findViewById(R.id.sub_tabs);
        TabLayout mainTabs = getActivity().findViewById(R.id.main_samsung_tabs);
        ViewPager2 viewPager2 = getActivity().findViewById(R.id.viewPager2);

        if (enabled) {
            mSelecting = true;
            adapter.notifyItemRangeChanged(0, adapter.getItemCount() - 1);
            toolbarLayout.setSelectModeBottomMenu(R.menu.select_mode_menu, item -> {
                item.setBadge(item.getBadge() + 1);
                Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT).show();
                return true;
            });
            toolbarLayout.showSelectMode();
            toolbarLayout.setSelectModeAllCheckedChangeListener((buttonView, isChecked) -> {
                if (checkAllListening) {
                    for (int i = 0; i < adapter.getItemCount() - 1; i++) {
                        selected.put(i, isChecked);
                        adapter.notifyItemChanged(i);
                    }
                }
                int count = 0;
                for (Boolean b : selected.values()) if (b) count++;
                toolbarLayout.setSelectModeCount(count);
            });
            toolbarLayout.showSelectModeBottomBar(false);
            subTabs.setEnabled(false);
            mainTabs.setEnabled(false);
            viewPager2.setUserInputEnabled(false);
            onBackPressedCallback.setEnabled(true);
        } else {
            mSelecting = false;

            mHandler.removeCallbacks(mShowBottomBarRunnable);

            for (int i = 0; i < adapter.getItemCount() - 1; i++) selected.put(i, false);
            adapter.notifyItemRangeChanged(0, adapter.getItemCount() - 1);

            toolbarLayout.setSelectModeCount(0);
            toolbarLayout.dismissSelectMode();
            subTabs.setEnabled(true);
            mainTabs.setEnabled(true);
            viewPager2.setUserInputEnabled(true);
            onBackPressedCallback.setEnabled(false);
        }
    }

    public void toggleItemSelected(int position) {
        selected.put(position, !selected.get(position));
        adapter.notifyItemChanged(position);

        checkAllListening = false;
        int count = 0;
        for (Boolean b : selected.values()) if (b) count++;
        toolbarLayout.setSelectModeAllChecked(count == adapter.getItemCount() - 1);
        toolbarLayout.setSelectModeCount(count);
        checkAllListening = true;
    }

I can secsesfully detect short and long clicks with my adapter like so

package si.wolf.sonoffc.adapters;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.TextView;

//import androidx.recyclerview.widget.RecyclerView;     //Google
import de.dlyt.yanndroid.oneui.view.RecyclerView;       //Samsung

import java.util.List;

import de.dlyt.yanndroid.oneui.view.Switch;

import si.wolf.sonoffc.R;
import si.wolf.sonoffc.models.Device;

// Create the basic adapter extending from RecyclerView.Adapter
// Note that we specify the custom ViewHolder which gives us access to our views
public class DevicesAdapter extends RecyclerView.Adapter<DevicesAdapter.ViewHolder> {

    // Events
    private ClickListener mclickListener;
    private ItemCheckChangedListener mCheckChangedListener;

    // ... view holder defined above...

    // Store a member variable for the contacts
    private List<Device> mDevices;

    // Pass in the contact array into the constructor
    public DevicesAdapter(List<Device> contacts) {
        mDevices = contacts;
    }

    // Provide a direct reference to each of the views within a data item
    // Used to cache the views within the item layout for fast access
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener, CompoundButton.OnCheckedChangeListener{
        // Your holder should contain a member variable
        // for any view that will be set as you render a row
        public TextView nameTextView;
        public TextView descriptionTextView;
        public Switch enabledSwich;

        // We also create a constructor that accepts the entire item row
        // and does the view lookups to find each subview
        public ViewHolder(View itemView) {
            // Stores the itemView in a public final member variable that can be used
            // to access the context from any ViewHolder instance.
            super(itemView);

            nameTextView = (TextView) itemView.findViewById(R.id.device_name);
            descriptionTextView = (TextView) itemView.findViewById(R.id.device_ip);
            enabledSwich = (Switch) itemView.findViewById(R.id.enabled_swich);

            //Events
            itemView.setOnLongClickListener(this);  // long click should be set up before standard click
            itemView.setOnClickListener(this);
        }

        //Click listener
        @Override
        public void onClick(View v) {
            mclickListener.onItemClick(v, getAdapterPosition());
        }

        @Override
        public boolean onLongClick(View v) {
            mclickListener.onItemLongClick(v, getAdapterPosition());
            // return false; // fire normal click also
            return true;
        }
        //Check changed listener
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (mCheckChangedListener != null) mCheckChangedListener.onItemCheckedChanged(buttonView, getAdapterPosition());
        }
    }

    // ... constructor and member variables

    // Usually involves inflating a layout from XML and returning the holder
    @Override
    public DevicesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);

        // Inflate the custom layout
        View contactView = inflater.inflate(R.layout.item_contact, parent, false);

        // Return a new holder instance
        ViewHolder viewHolder = new ViewHolder(contactView);
        return viewHolder;
    }

    // Involves populating data into the item through holder
    @Override
    public void onBindViewHolder(DevicesAdapter.ViewHolder holder, int position) {
        // Get the data model based on position
        Device device = mDevices.get(position);

        // Set item views based on your views and data model
        TextView textView_name = holder.nameTextView;
        textView_name.setText(device.getName());
        TextView textView_description = holder.descriptionTextView;
        textView_description.setText(device.getIPAddress());
        Switch enabled_switch = holder.enabledSwich;
        enabled_switch.setChecked(device.isOnline());

        //To implement this outside view here: https://stackoverflow.com/a/49969478/17826480
        holder.enabledSwich.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.d("demo", "onChecked: position: " + position + " | name: " + device.getName());
            }
        });
    }

    // Returns the total count of items in the list
    @Override
    public int getItemCount() {
        return mDevices.size();
    }

    //Events

    // convenience method for getting data at click position
    public String getItem(int id) {
        return mDevices.get(id).getName();
    }

    //Click events
    // allows clicks events to be caught
    // parent activity will implement this method to respond to click events
    public void setOnItemClickListener(ClickListener listener) {
        mclickListener = listener;
    }

    public interface ClickListener {
        void onItemClick(View v, int position);
        void onItemLongClick(View v, int position);
    }

    // parent activity will implement this method to respond to click events
    public interface ItemCheckChangedListener {
        void onItemCheckedChanged(View view, int position);
    }

    //Listens for button toggle
    public void setToggleListener(CompoundButton.OnCheckedChangeListener listener)
    {

    }
}

then in MainActivity onCreate, you bind to them

        //Handle click events
        adapter.setOnItemClickListener(new DevicesAdapter.ClickListener() {
            String TAG = "clicky";
            @Override
            public void onItemClick(View v, int position) {
                Log.d(TAG, "Click: " + adapter.getItem(position));
                //Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();

            }
            @Override
            public void onItemLongClick(View v, int position) {
                Log.d(TAG, "Long Click");
                //Toast.makeText(this, "You long clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
                if (!mSelecting) setSelecting(true);
                toggleItemSelected(position);
                rvDevices.seslStartLongPressMultiSelection(); //RecycleView
            }
        });

My view looks like this activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<de.dlyt.yanndroid.oneui.layout.ToolbarLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/toolbar_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:title="@string/app_name"
    app:subtitle="@string/app_description"
    app:expandable="true"
    app:expanded="true"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/item_background_color">

        <!-- Google --><!--
            <androidx.recyclerview.widget.RecyclerView
        -->

        <!-- Samsung -->
        <de.dlyt.yanndroid.oneui.view.RecyclerView
            android:id="@+id/rvDevices"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</de.dlyt.yanndroid.oneui.layout.ToolbarLayout>

my recycleView row looks like this (probably doesn't matter for multiselect but just in case)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp"
    android:background="?android:attr/selectableItemBackground">

    <TextView
        android:id="@+id/device_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:text="Relay"
        android:textSize="16dp"
        android:textStyle="bold"
        android:layout_marginStart="@dimen/sesl_action_bar_content_inset"
        app:layout_constraintEnd_toStartOf="@+id/enabled_swich"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/device_ip"
        android:layout_width="0dp"
        android:layout_height="wrap_content"

        android:layout_marginTop="4dp"
        android:layout_marginEnd="8dp"
        android:text="192.168.88.19"
        android:layout_marginStart="@dimen/sesl_action_bar_content_inset"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/enabled_swich"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/device_name"
        app:layout_constraintVertical_bias="0.0" />

    <de.dlyt.yanndroid.oneui.view.Switch
        android:id="@+id/enabled_swich"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="2dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/device_ip"
        app:layout_constraintTop_toTopOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

and my bottomBar which I would like to show when multiselecting (select_mode_menu) looks like this

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/move"
        android:icon="@drawable/ic_oui_move"
        android:title="Move"
        app:showAsAction="always" />

    <item
        android:id="@+id/delete"
        android:icon="@drawable/ic_ouid_delete"
        android:title="Delete"
        app:showAsAction="always" />

    <item
        android:id="@+id/add"
        android:icon="@drawable/ic_oui_list_add"
        android:title="Add"
        app:showAsAction="always" />

    <item
        android:id="@+id/edit"
        android:icon="@drawable/ic_oui3_edit"
        android:title="Edit"
        app:showAsAction="always" />

    <item
        android:id="@+id/item1"
        android:title="Menu Item 1"
        app:showAsAction="never" />

    <item
        android:id="@+id/item2"
        android:title="Menu Item 2"
        app:showAsAction="never" />

    <item
        android:id="@+id/item3"
        android:title="Menu Item 3"
        app:showAsAction="never" />

</menu>

Now I have a bit of trouble, since your I have no idea what theese in setSelecting do (yea, I am trying to adapt from here: https://github.com/OneUIProject/OneUI-Design-Library/blob/062c469b35ce127eeb84c0130725ead7032fc516/app/src/main/java/de/dlyt/yanndroid/oneuiexample/tabs/IconsTab.java#L494

TabLayout subTabs = getActivity().findViewById(R.id.sub_tabs);
        TabLayout mainTabs = getActivity().findViewById(R.id.main_samsung_tabs);
        ViewPager2 viewPager2 = getActivity().findViewById(R.id.viewPager2);

as well as what is showSelectModeBottomBar(false); suppose to do (toolbarLayout, nor Drawer layout seem to have it) and I don't realy know how you then handle back button press

and yea, I am still using the old oneUI library, because it has better documentation and it is the only lib that supports both OneUI3 (which I prefer) and OneUI4 theme

and I still have no idea, why there are 2 libraries https://github.com/OneUIProject/sesl https://github.com/OneUIProject/oneui-design

that both seam to do the same thing (which is better :smile: ?)

Hope you can help me and Thanks for Anwsering and Best Regards

salvogiangri commented 2 years ago

The new oneui-design module should not be confused with the old OneUI Design Lib, the new design module is an addition to our new oneui-core libs, and contains for the most part only backported components/widget from the old lib.

ToolbarLayout select mode methods are purely aesthetic and are meant to be a replacement for the Contextual Action Mode you should instead use if you're using the new core libs (you can always use the new design module which has a backported ToolbarLayout compatible with the new core libs, but imho I'd rather use ActionMode), so use those to change the UI of the AppBar depending on what you want to do (show/dismiss the select mode, set the selected items count, show/hide the bottom menu bar etc.). The item selection code however must be coded by you, the code in our Sample app is decent if you want to take a look on how we think you should use the ToolbarLayout select mode. The sesl longPress API's in RecyclerView are instead used to handle the press and hold gestures.

We're sorry if there's still no documentation ready for the new libs but both me and Yann have been extremely busy with other stuff, all the new documentation will be available soon in our new wiki page.

Yanndroid commented 2 years ago

We have 3 libraries in this organization:

oneui-core (aka sesl)

This one is a modified androidx and material library, here you will find all the stock components, but themed as oneui.

oneui-design

This is sort of a wrapper for the oneui-core and contains custom classes like ToolbarLayout which are making it easier for dev to make apps. This is also the recommended library to use.

OneUI Design Library

This library is deprecated and is replaced by oneui-design, but it still supports oneui 3

We haven't added the action (aka select) and search mode the new sample app but the library does have it. But you can check the old wiki and sample for how to use it (Only difference might be method names, ex: selectmode -> actionmode).

(I see @BlackMesa123 was faster for responding but I'll post it anyway)

salvogiangri commented 2 years ago

(I see @BlackMesa123 was faster for responding but I'll post it anyway)

You had to, couldn't explain it better than you did😂

Yanndroid commented 2 years ago

what is showSelectModeBottomBar(false); suppose to do

This only exist in the old lib I think, and what it does is disable the BottomBar. So if you don't want to show a BottomBar when the SelectMode is enabled you use this. (Honestly I don't remember why I added this😅)

I don't realy know how you then handle back button press

It should be handled automatically be the ToolbarLayout. (see here)

salvogiangri commented 2 years ago

This only exist in the old lib I think, and what it does is disable the BottomBar. So if you don't want to show a BottomBar when the SelectMode is enabled you use this. (Honestly I don't remember why I added this😅)

I think I've added it somewhere in-between 2.3.0 and 2.4.0, to simulate the bottom bar behavior in Samsung apps (it shows when the longpress listener onEnd method is called), but the default behavior of the bottom bar is the same as it always have been

veso266 commented 2 years ago

Thanks guys for all this, wiki comes when it comes, but we still have the old wiki so :smile: there is documentation

since my app is coded in the old lib, I guess will just have to make multiselect work somehow (easier to swich libs completly because of a feature :smile:)

veso266 commented 2 years ago

Ah, some small progress I was kinda able to make multiselect mode work

        //Handle click events
        adapter.setOnItemClickListener(new DevicesAdapter.ClickListener() {
            String TAG = "clicky";
            @Override
            public void onItemClick(View v, int position) {
                Log.d(TAG, "Click: " + adapter.getItem(position));
                if (mSelecting) toggleItemSelected(position);
                //Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();

            }
            @Override
            public void onItemLongClick(View v, int position) {
                Log.d(TAG, "Long Click");
                //Toast.makeText(this, "You long clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
                if (!mSelecting) setSelecting(true);
                toggleItemSelected(position);
                rvDevices.seslStartLongPressMultiSelection();
            }
        });

    int selectedElement = -1;
    public void setSelecting(boolean enabled) {
        if (enabled) {
            mSelecting = true;
            adapter.notifyItemRangeChanged(0, adapter.getItemCount());
            toolbarLayout.setSelectModeBottomMenu(R.menu.select_mode_menu, item -> {
                item.setBadge(item.getBadge() + 1);
                Toast.makeText(this, "Item: " + item.getTitle() +  (String.format(" Ime: %s | IP: %s", adapter.getItem(selectedElement), adapter.getItemDescription(selectedElement))), Toast.LENGTH_SHORT).show();
                //Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT).show();
                return true;
            });
            toolbarLayout.showSelectMode();
            toolbarLayout.setSelectModeAllCheckedChangeListener((buttonView, isChecked) -> {
                if (checkAllListening) {
                    for (int i = 0; i < adapter.getItemCount(); i++) {
                        selected.put(i, isChecked);
                        adapter.notifyItemChanged(i);
                    }
                }
                int count = 0;
                for (Boolean b : selected.values()) if (b) count++;
                toolbarLayout.setSelectModeCount(count);
            });
            //toolbarLayout.showSelectModeBottomBar(false);

        } else {
            mSelecting = false;

            for (int i = 0; i < adapter.getItemCount(); i++) selected.put(i, false);
            adapter.notifyItemRangeChanged(0, adapter.getItemCount());

            toolbarLayout.setSelectModeCount(0);
            toolbarLayout.dismissSelectMode();
        }
    }

    //select mode dismiss on back
    @Override
    public void onBackPressed() {
        if (mSelecting) {
            setSelecting(false);
            return;
        }
        else
            super.onBackPressed();
        Log.d("Button:", "Back button pressed!!");

    }

    public void toggleItemSelected(int position) {
        selected.put(position, !selected.get(position));
        adapter.notifyItemChanged(position);

        selectedElement = position;

        checkAllListening = false;
        int count = 0;
        for (Boolean b : selected.values()) if (b) count++;
        toolbarLayout.setSelectModeAllChecked(count == adapter.getItemCount());
        toolbarLayout.setSelectModeCount(count);
        checkAllListening = true;
    }

it now looks like this Screenshot_20220628-184050_Sonoff Mobile App

still not able to draw the little checkbox next to the item that is selected, and still not able to reliably get row number that is selected, but it is a start :smile:

salvogiangri commented 2 years ago

Remember you do not necessarily need to call seslStartLongPressMultiSelection in the item long press listener, since this will only work if you have set a long press listener in your RecyclerView with seslSetLongPressMultiSelectionListener. To see an example of what seslLongPressMultiSelect does, open a Samsung app that has a list and scroll the list while pressing and holding an item. The rest seems ok, you just need to adjust your list item view to support a checkbox and polish the code a bit since there's still a lot of the dummy stuff we put in our example code (such as the badge for the bottom menu when an item is clicked), remember to use that just as reference since 90% of the time we code that stuff in rush since we want to just showcase how does it looks

veso266 commented 2 years ago

Thanks, its good now :smile: Screenshot_20220628-195859_Sonoff Mobile App

my row looks like this now

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp"
    android:background="?android:attr/selectableItemBackground">

    <CheckBox
        android:id="@+id/selected_checkbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@null"
        android:clickable="false"
        android:focusable="false"
        android:visibility="gone"
        android:layout_marginLeft="15dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/device_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:text="Relay"
        android:textSize="16dp"
        android:textStyle="bold"
        android:layout_marginStart="@dimen/sesl_action_bar_content_inset"
        app:layout_constraintEnd_toStartOf="@+id/enabled_swich"
        app:layout_constraintStart_toEndOf="@+id/selected_checkbox"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/device_ip"
        android:layout_width="0dp"
        android:layout_height="wrap_content"

        android:layout_marginTop="4dp"
        android:layout_marginEnd="8dp"
        android:text="192.168.88.19"
        android:layout_marginStart="@dimen/sesl_action_bar_content_inset"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/enabled_swich"
        app:layout_constraintStart_toEndOf="@+id/selected_checkbox"
        app:layout_constraintTop_toBottomOf="@id/device_name"
        app:layout_constraintVertical_bias="0.0" />

    <de.dlyt.yanndroid.oneui.view.Switch
        android:id="@+id/enabled_swich"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="2dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/device_ip"
        app:layout_constraintTop_toTopOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

my events are like this

//Handle click events
        adapter.setOnItemClickListener(new DevicesAdapter.ClickListener() {
            String TAG = "clicky";
            @Override
            public void onItemClick(View v, int position) {
                Log.d(TAG, "Click: " + adapter.getItem(position));
                if (mSelecting) {
                    toggleItemSelected(position);
                    selectedElement = position;
                }
                //Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();

            }
            @Override
            public void onItemLongClick(View v, int position) {
                Log.d(TAG, "Long Click");
                //Toast.makeText(this, "You long clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
                if (!mSelecting) setSelecting(true);
                toggleItemSelected(position);
                selectedElement = position;
                rvDevices.seslStartLongPressMultiSelection();
            }
        });

and my selecting methods

 Stack<Integer> selectedStack = new Stack<Integer>(); //This stack ensours that selected elements is always uvailable
    public void setSelecting(boolean enabled) {
        if (enabled) {
            mSelecting = true;
            adapter.notifyItemRangeChanged(0, adapter.getItemCount());
            toolbarLayout.setSelectModeBottomMenu(R.menu.select_mode_menu, item -> {
                Toast.makeText(this, "Item: " + item.getTitle() +  (String.format(" Ime: %s | IP: %s", adapter.getItem(selectedStack.peek()), adapter.getItemDescription(selectedStack.peek()))), Toast.LENGTH_SHORT).show();
                return true;
            });
            toolbarLayout.showSelectMode();
            toolbarLayout.setSelectModeAllCheckedChangeListener((buttonView, isChecked) -> {
                if (checkAllListening) {
                    for (int i = 0; i < adapter.getItemCount(); i++) {
                        selected.put(i, isChecked);
                        adapter.notifyItemChanged(i);
                    }
                }
                int count = 0;
                for (Boolean b : selected.values()) if (b) count++;
                toolbarLayout.setSelectModeCount(count);
            });
            //toolbarLayout.showSelectModeBottomBar(false);

        } else {
            mSelecting = false;

            for (int i = 0; i < adapter.getItemCount(); i++) selected.put(i, false);
            adapter.notifyItemRangeChanged(0, adapter.getItemCount());

            toolbarLayout.setSelectModeCount(0);
            toolbarLayout.dismissSelectMode();
        }
    }

    //select mode dismiss on back
    @Override
    public void onBackPressed() {
        if (mSelecting) {
            setSelecting(false);
            return;
        }
        else
            super.onBackPressed();
        Log.d("Button:", "Back button pressed!!");

    }

    public void toggleItemSelected(int position) {
        selected.put(position, !selected.get(position));
        adapter.notifyItemChanged(position);

        if (selected.get(position))
            selectedStack.push(position);
        else
            selectedStack.pop();

        checkAllListening = false;
        int count = 0;
        for (Boolean b : selected.values()) if (b) count++;
        toolbarLayout.setSelectModeAllChecked(count == adapter.getItemCount());
        toolbarLayout.setSelectModeCount(count);
        checkAllListening = true;
    }

my deviceAdapter.java

package si.wolf.sonoffc.adapters;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

//import androidx.recyclerview.widget.RecyclerView;     //Google
import de.dlyt.yanndroid.oneui.view.RecyclerView;       //Samsung

import java.util.List;

import de.dlyt.yanndroid.oneui.view.Switch;

import si.wolf.sonoffc.R;
import si.wolf.sonoffc.models.Device;

// Create the basic adapter extending from RecyclerView.Adapter
// Note that we specify the custom ViewHolder which gives us access to our views
public class DevicesAdapter extends RecyclerView.Adapter<DevicesAdapter.ViewHolder> {

    // Events
    private ClickListener mclickListener;
    private ItemCheckChangedListener mCheckChangedListener;

    // ... view holder defined above...

    // Store a member variable for the contacts
    private List<Device> mDevices;

    // Pass in the contact array into the constructor
    public DevicesAdapter(List<Device> contacts) {
        mDevices = contacts;
    }

    // Provide a direct reference to each of the views within a data item
    // Used to cache the views within the item layout for fast access
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener, CompoundButton.OnCheckedChangeListener{
        // Your holder should contain a member variable
        // for any view that will be set as you render a row
        public TextView nameTextView;
        public TextView descriptionTextView;
        public Switch enabledSwich;
        public CheckBox selected_checkbox;

        // We also create a constructor that accepts the entire item row
        // and does the view lookups to find each subview
        public ViewHolder(View itemView) {
            // Stores the itemView in a public final member variable that can be used
            // to access the context from any ViewHolder instance.
            super(itemView);

            nameTextView = (TextView) itemView.findViewById(R.id.device_name);
            descriptionTextView = (TextView) itemView.findViewById(R.id.device_ip);
            enabledSwich = (Switch) itemView.findViewById(R.id.enabled_swich);
            selected_checkbox = (CheckBox) itemView.findViewById(R.id.selected_checkbox);

            //Events
            itemView.setOnLongClickListener(this);  // long click should be set up before standard click
            itemView.setOnClickListener(this);
        }

        //Click listener
        @Override
        public void onClick(View v) {
            mclickListener.onItemClick(v, getAdapterPosition());
        }

        @Override
        public boolean onLongClick(View v) {
            mclickListener.onItemLongClick(v, getAdapterPosition());
            // return false; // fire normal click also
            return true;
        }
        //Check changed listener
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (mCheckChangedListener != null) mCheckChangedListener.onItemCheckedChanged(buttonView, getAdapterPosition());
        }
    }

    // ... constructor and member variables

    // Usually involves inflating a layout from XML and returning the holder
    @Override
    public DevicesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);

        // Inflate the custom layout
        View contactView = inflater.inflate(R.layout.device_row, parent, false);

        // Return a new holder instance
        ViewHolder viewHolder = new ViewHolder(contactView);
        return viewHolder;
    }

    // Involves populating data into the item through holder
    @Override
    public void onBindViewHolder(DevicesAdapter.ViewHolder holder, int position) {
        // Get the data model based on position
        Device device = mDevices.get(position);

        // Set item views based on your views and data model
        TextView textView_name = holder.nameTextView;
        textView_name.setText(device.getName());
        TextView textView_description = holder.descriptionTextView;
        textView_description.setText(device.getIPAddress());
        Switch enabled_switch = holder.enabledSwich;
        enabled_switch.setChecked(device.isOnline());

        //To implement this outside view here: https://stackoverflow.com/a/49969478/17826480
        holder.enabledSwich.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.d("demo", "onChecked: position: " + position + " | name: " + device.getName());
            }
        });

        //Make Selected item have checkbox (yea, I know there is probably a better way then to make mSelecting & selected array static but I don't know it right now :)
        holder.selected_checkbox.setVisibility(si.wolf.sonoffc.MainActivity.mSelecting ? View.VISIBLE : View.GONE);
        if (si.wolf.sonoffc.MainActivity.mSelecting)
            holder.selected_checkbox.setChecked(si.wolf.sonoffc.MainActivity.selected.get(position));
    }

    // Returns the total count of items in the list
    @Override
    public int getItemCount() {
        return mDevices.size();
    }

    //Events

    // convenience method for getting data at click position
    public String getItem(int id) {
        return mDevices.get(id).getName();
    }
    public String getItemDescription(int id) { return mDevices.get(id).getIPAddress(); }

    //Click events
    // allows clicks events to be caught
    // parent activity will implement this method to respond to click events
    public void setOnItemClickListener(ClickListener listener) {
        mclickListener = listener;
    }

    public interface ClickListener {
        void onItemClick(View v, int position);
        void onItemLongClick(View v, int position);
    }

    // parent activity will implement this method to respond to click events
    public interface ItemCheckChangedListener {
        void onItemCheckedChanged(View view, int position);
    }
}

the animation between android:visibility="gone" and android:visibility="visible" is stil preaty rough but it works its just rough :smile:

even managed to implement the quick multiselection thingy

//Multi selection
        rvDevices.seslSetLongPressMultiSelectionListener(new RecyclerView.SeslLongPressMultiSelectionListener() {
            @Override
            public void onItemSelected(RecyclerView view, View child, int position, long id) {
                if (adapter.getItemViewType(position) == 0) {
                    toggleItemSelected(position);
                }
            }

            @Override
            public void onLongPressMultiSelectionStarted(int x, int y) {
                //drawerLayout.showSelectModeBottomBar(false);
            }

            @Override
            public void onLongPressMultiSelectionEnded(int x, int y) {
               // mHandler.postDelayed(mShowBottomBarRunnable, 300);
            }
        });

Didn't even know I can do this, so thanks for teaching me that trick, it makes quick selection so much easier