Syncing Data Between Two RecyclerViews in Android BottomsheetDialogueFragment

17 Views Asked by At

I have a bottomsheet fragment and I have implemented two recyclerviews in it. The bottomsheet takes the argument of a arraylist of a custom datatype "UserMedicalData". This custom type has an argument of type boolean .If the boolean is true it should be added to the dataset of recyclerview b and should be check marked in recyclerview A. if we click on an item in recyclerview A , it should change it's boolean status . If the boolean is true it should be added to the recyclerview B anmd should be marked checked in recyclerview A. If it was already marked checked , it should tutn its boolean status to false, uncheck itself and remove itself from the recyclerview B. Also if the item is clicked in recyclerview B ,it should turn its boolean status to false and delete itself from recyclerview B's dataset and uncheck itslef from the recyclerview A. In simple terms , if the item's boolean is true it should be added to recyclerview B , iof not it should be removed from recyclerview B. In all cases, the boolean status should be reflected in the recyclerview A. I have implemented a soultion , please help me optimize it .Here are the files

The bottomsheet fragment:

public class DiseasesBottomSheetFragment  extends BottomSheetDialogFragment implements SelectDiseaseBottomSheetView, View.OnTouchListener, TextWatcher, View.OnClickListener  {

    private SelectDiseaseBottomSheetViewHolder holder;
    private SelectDiseaseBottomSheetPresenter presenter;

    private AllDiseasesAdapter adapter;
    private SelectedDiseaseBottomSheetAdapter selectedDiseasesAdapter;
    private DiseaseFragmentCallback callback;
    private BottomSheetBehavior<View> bottomSheetBehavior;


    public DiseasesBottomSheetFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        WindowManager windowManager = requireActivity().getWindowManager();
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        int screenHeight = displayMetrics.heightPixels;
        int desiredHeight = (int) (screenHeight * 0.94);


        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) view.getParent()).getLayoutParams();
        bottomSheetBehavior = (BottomSheetBehavior<View>) params.getBehavior();
        assert bottomSheetBehavior != null;
        bottomSheetBehavior.setPeekHeight(desiredHeight);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_diseases_bottom_sheet, container, false);
        initGui(view);
        initVariables();
        recieveArguments();
        setItemsForAllDiseasesRV();
        setItemsForSelectedDiseasesRV();
        setListeners();
        return view;
    }
    private void setItemsForSelectedDiseasesRV() {
        if (!getSelectedItems().isEmpty()){
            setSelectedDiseasesRV(presenter.getItems());
        }
    }
    private void setItemsForAllDiseasesRV() {
        if (Objects.requireNonNull(holder.getSearchEditText().getText()).toString().isEmpty()){
            if (!presenter.getAllDiseasesList().isEmpty()){
                setAllDiseasesRV(presenter.getAllDiseasesList());
            }
            else{
                Toast.makeText(getContext(), "Please retry again later.", Toast.LENGTH_SHORT).show();
            }
        }
        else{
            setUpFilteredRV();
        }
    }

    private void setUpFilteredRV() {
    }

    private void recieveArguments() {
        // Retrieve arguments
        Bundle args = getArguments();
        if (args != null) {
            presenter.ProcessArguments(args);
        }
    }

    @Override
    public void addToSelectedItems(int position) {
        if (!getSelectedItems().contains(getAllItems().get(position))){
            getSelectedItems().add(getAllItems().get(position));
        }
    }

    private void setListeners() {
        holder.getDoneButton().setOnClickListener(this);
        holder.getSearchEditText().setOnTouchListener(this);
        holder.getSearchEditText().addTextChangedListener(this);

    }
    private void initGui(View view) {
        holder = new SelectDiseaseBottomSheetViewHolder(view);
    }
    private void initVariables() {presenter = new SelectDiseaseBottomSheetPresenter( this, getContext());}

    private AdpaterViewItemClickedListener adpaterViewItemClickedListener = new AdpaterViewItemClickedListener() {
        @Override
        public void onAdatviewItemClicked(int position) {}

        @Override
        public void onAdatviewItemClicked(int position, int requestID) {
            if (requestID == AppConstants.DISEASE_CLICKED_TO_ADD_TO_LIST) {
                getAllItems().get(position).setSelected(true);
                if (!getSelectedItems().contains(getAllItems().get(position))){
                    addToSelectedItems(position);
                    if (!getSelectedItems().isEmpty()){
                        setItemsForSelectedDiseasesRV();
                        selectedDiseasesAdapter.notifyDataSetChanged();
                    }
                }
            }
            if (requestID == AppConstants.DISEASE_CLICKED_TO_REMOVE_FROM_LIST) {
                getAllItems().get(position).setSelected(false);
                if (!getSelectedItems().isEmpty() && getSelectedItems().contains(getAllItems().get(position))){
                    getSelectedItems().remove(getAllItems().get(position));
                    selectedDiseasesAdapter.notifyDataSetChanged();
                }

            }
            if (requestID == AppConstants.SELECTED_DISEASE_CLICKED) {
                try {
                    if(getSelectedItems() != null && getSelectedItems().size() > 0) {
                        uncheckRemovedItemFromAllItemList(getSelectedItems().get(position).getId());
                    }
                    getSelectedItems().remove(getSelectedItems().get(position));
                    selectedDiseasesAdapter.notifyItemRemoved(position);
                } catch (IndexOutOfBoundsException e) {
                    System.out.println("Disease already deleted");
                }
            }
        }
        public void uncheckRemovedItemFromAllItemList(int removedItemId) {
            for(int i=0; i<getAllItems().size(); i++) {
                if(getAllItems().get(i).getId() == removedItemId) {
                    getAllItems().get(i).setSelected(false);
                    adapter.notifyItemChanged(i);
                    break;
                }
            }
        }

        @Override
        public void onAdatviewItemClicked(int position, int requestID, String s) {}

        @Override
        public void onAdatviewItemClicked(UserMedicalData userMedicalData, int requestID) {
            if (requestID == AppConstants.DISEASE_CLICKED_TO_ADD_TO_LIST) {
                for (int i=0; i<=getAllItems().size();i++){
                    if (getAllItems().get(i).getId()==userMedicalData.getId()){
                        getAllItems().get(i).setSelected(true);
                        addToSelectedItems(i);
                        if (!getSelectedItems().isEmpty()){
                            setItemsForSelectedDiseasesRV();
                            selectedDiseasesAdapter.notifyDataSetChanged();
                        }

                        break;
                    }
                }
            }
            if (requestID == AppConstants.DISEASE_CLICKED_TO_REMOVE_FROM_LIST) {
                for (int i=0; i<=getAllItems().size();i++){
                    if (getAllItems().get(i).getId()==userMedicalData.getId()){
                        getAllItems().get(i).setSelected(false);
                        if (!getSelectedItems().isEmpty() && getSelectedItems().contains(getAllItems().get(i))){
                            getSelectedItems().remove(getAllItems().get(i));
                            selectedDiseasesAdapter.notifyDataSetChanged();
                        }
                        break;
                    }
                }
            }
        }
    };


    @Override
    public void filterList() {
        if (presenter.getFilteredArrayList() != null) {
            if (adapter != null) {
                adapter.filter(presenter.getFilteredArrayList());
            }
        }
    }

    @Override
    public void setNoRecordsVisibility(boolean isVisible) {
        if (isVisible){
            holder.getNoRecordsFound().setVisibility(View.VISIBLE);
        }else {
            holder.getNoRecordsFound().setVisibility(View.GONE);
        }
    }
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.search_text_view:
                break;
            case R.id.done_button:
                sendDataToActivity();
                dismiss();
                break;
        }
    }
    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        Bundle args = new Bundle();
        args.putParcelableArrayList("selectedArray",new ArrayList<>(getSelectedItems()));
        setArguments(args);
        super.onDismiss(dialog);
    }

    @Override
    public List<UserMedicalData> getAllItems() {return presenter.getAllDiseasesList();}

    @Override
    public List<UserMedicalData> getSelectedItems() {return presenter.getItems();}

    @Override
    public void setAllDiseasesRV(List<UserMedicalData> data) {
        if (!data.isEmpty()) {
            adapter = new AllDiseasesAdapter(getContext(),adpaterViewItemClickedListener, data);
            holder.getAllDiseasesRV().setAdapter(adapter);
        }
    }
    @Override
    public void setSelectedDiseasesRV(List<UserMedicalData> items) {
        if (!items.isEmpty()) {
            selectedDiseasesAdapter = new SelectedDiseaseBottomSheetAdapter(getContext(), items,adpaterViewItemClickedListener);
            holder.getSelectedDiseasesRV().setAdapter(selectedDiseasesAdapter);
        }
    }
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        view.setFocusable(true);
        view.setFocusableInTouchMode(true);
        return false;
    }
    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
    @Override
    public void afterTextChanged(Editable editable) {
        if (editable != null) {
            presenter.filter(editable.toString());
        }
        InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            imm.toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);
        }
    }
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof DiseaseFragmentCallback) {
            callback = (DiseaseFragmentCallback) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement FragmentCallback");
        }
    }
    private void sendDataToActivity() {
        if (callback != null) {
            callback.onDataReceived(presenter.getItems());
        }
    }
}

It's presenter:

public class SelectDiseaseBottomSheetPresenter implements ServerConnectListener {

    private SelectDiseaseBottomSheetView view;
    private Context context;
    private List<UserMedicalData> allDiseasesList;
    private List<UserMedicalData> items = new ArrayList<>();
    private List<UserMedicalData> filteredArrayList = new ArrayList<>();

    public SelectDiseaseBottomSheetPresenter(SelectDiseaseBottomSheetView view, Context context) {
        this.view = view;
        this.context = context;
    }

    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public List<UserMedicalData> getAllDiseasesList() {
        return allDiseasesList;
    }

    public void setAllDiseasesList(List<UserMedicalData> allDiseasesList) {
        this.allDiseasesList = allDiseasesList;
    }

    public List<UserMedicalData> getItems() {
        return items;
    }

    public void setItems(List<UserMedicalData> items) {
        this.items = items;
    }

    public List<UserMedicalData> getFilteredArrayList() {
        return filteredArrayList;
    }

    public void setFilteredArrayList(List<UserMedicalData> filteredArrayList) {
        this.filteredArrayList = filteredArrayList;
    }

    public void filter(String toString) {
        filteredArrayList = new ArrayList<>();
        for (UserMedicalData item : view.getAllItems()) {
            if (item.getTitle().toLowerCase().contains(toString.toLowerCase())) {
                view.setNoRecordsVisibility(false);
                filteredArrayList.add(item);
            }
        }
        if (filteredArrayList.size() == 0) {
            view.setNoRecordsVisibility(true);
        }else {
            view.setNoRecordsVisibility(false);
        }
        view.filterList();
    }

    public void ProcessArguments(Bundle args){
        if (args.containsKey("all_items_array")){
            allDiseasesList = args.getParcelableArrayList("all_items_array");
            for (int i = 0; i < allDiseasesList.size(); i++){
                if (allDiseasesList.get(i).getSelected()){
                    view.addToSelectedItems(i);
                }
            }
        }
    }
    @Override
    public void onSuccess(ServerResponse response) {

    }
    @Override
    public void onFailure(ServerResponse response) {

    }
    @Override
    public void onSessionExpiry(ServerResponse response) {

    }
}


It's view interface:

public interface SelectDiseaseBottomSheetView {
    List<UserMedicalData> getAllItems();
    List<UserMedicalData> getSelectedItems();
    void setAllDiseasesRV(List<UserMedicalData> items);
    void setSelectedDiseasesRV(List<UserMedicalData> items);
    void filterList();
    void setNoRecordsVisibility(boolean isVisible);
    void addToSelectedItems(int position);
}

The adatViewClickListener interface:

public interface AdpaterViewItemClickedListener {

    void onAdatviewItemClicked(int position);

    void onAdatviewItemClicked(int position, int requestID);

    void onAdatviewItemClicked(int position, int requestID, String s);
    default void onAdatviewItemClicked(UserMedicalData userMedicalData, int requestID){

    }

}

The AllDiseases Adapter for recyclerview A:

public class AllDiseasesAdapter extends RecyclerView.Adapter<AllDiseasesViewHolder>{

    private Context context;
    private AdpaterViewItemClickedListener listener;
    private List<UserMedicalData> data;

    public AllDiseasesAdapter(Context context, AdpaterViewItemClickedListener listener, List<UserMedicalData> data) {
        this.context = context;
        this.listener = listener;
        this.data = data;
    }

    @NonNull
    @Override
    public AllDiseasesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.items_with_checkbox_layout, parent, false);
        return new AllDiseasesViewHolder(view, listener, context);
    }

    @Override
    public void onBindViewHolder(@NonNull AllDiseasesViewHolder holder, int position) {
        holder.getItemText().setText(data.get(position).getTitle());
        holder.bindData(data.get(position));
        if (data.get(position).getSelected()){
            holder.getCheckBox().setChecked(data.get(position).getSelected());
        }else{
            holder.getCheckBox().setChecked(false);

        }
    }
    public void filter(List<UserMedicalData> filteredArrayList) {
        data = new ArrayList<>();
        if (filteredArrayList != null) {
            data = filteredArrayList;
            notifyDataSetChanged();
        }
    }

    @Override
    public int getItemCount() {
        return data.size();
    }
}

It's viewholder:

public class AllDiseasesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private AdpaterViewItemClickedListener listener;
    private Context context;
    public ConstraintLayout itemLayout;
    public TextView itemText;
    public CheckBox checkBox;
    public UserMedicalData userMedicalData;

    public AllDiseasesViewHolder(@NonNull View view, AdpaterViewItemClickedListener listener, Context context) {
        super(view);
        initGui(view);
        initVariables(listener, context);
        setListeners();
    }

    private void initVariables(AdpaterViewItemClickedListener listener, Context context) {
        this.listener = listener;
        this.context = context;
    }

    public TextView getItemText() {
        return itemText;
    }

    public CheckBox getCheckBox() {
        return checkBox;
    }

    private void initGui(View view) {
        itemLayout = view.findViewById(R.id.item_layout);
        itemText = view.findViewById(R.id.text);
        checkBox = view.findViewById(R.id.checkbox);
    }

    private void setListeners() {
        itemLayout.setOnClickListener(this);
    }

    public void bindData(UserMedicalData userMedicalData){
        this.userMedicalData=userMedicalData;

    }


    @Override
    public void onClick(View view) {
        int viewId = view.getId();
        if (viewId == itemLayout.getId()) {
            if (getCheckBox().isChecked()){
                listener.onAdatviewItemClicked(userMedicalData, AppConstants.DISEASE_CLICKED_TO_REMOVE_FROM_LIST);
                getCheckBox().setChecked(false);
            }
            else{
                listener.onAdatviewItemClicked(userMedicalData, AppConstants.DISEASE_CLICKED_TO_ADD_TO_LIST);
                getCheckBox().setChecked(true);
            }
        }
    }
}

The selecteddisease Adapter for recyclerview B:

public class SelectedDiseaseBottomSheetAdapter extends RecyclerView.Adapter<SelectedDiseaseViewHolder> {

    private List<UserMedicalData> data;
    private Context context;
    private AdpaterViewItemClickedListener listener;


    public SelectedDiseaseBottomSheetAdapter(Context context, List<UserMedicalData> data, AdpaterViewItemClickedListener listener) {
        this.context = context;
        this.data = data;
        this.listener = listener;
    }

    @NonNull
    @Override
    public SelectedDiseaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.selected_disease_bottomsheet_layout, parent, false);
        return new SelectedDiseaseViewHolder(view, listener, context);
    }

    @Override
    public void onBindViewHolder(@NonNull SelectedDiseaseViewHolder holder, int position) {
        holder.getItemText().setText(data.get(position).getTitle());

    }

    @Override
    public int getItemCount() {
        return data.size();
    }
}

And it's viewholder:

public class SelectedDiseaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    public TextView itemText;
    private AdpaterViewItemClickedListener listener;
    private Context context;

    public SelectedDiseaseViewHolder(@NonNull View view, AdpaterViewItemClickedListener listener, Context context) {
        super(view);
        initGui(view);
        initVariables(listener, context);
        setListeners();
    }

    private void initVariables(AdpaterViewItemClickedListener listener, Context context) {
        this.listener = listener;
        this.context = context;
    }

    public TextView getItemText() {
        return itemText;
    }

    private void initGui(View view) {
        itemText = view.findViewById(R.id.text);
    }

    private void setListeners() {
        itemText.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        int viewId = view.getId();
        if (viewId == itemText.getId()) {
            listener.onAdatviewItemClicked(getAbsoluteAdapterPosition(), AppConstants.SELECTED_DISEASE_CLICKED);
        }
    }
}

Lastly here is the datamodel for the items of the arraylist set as dataset of these recyclerviews:

@Keep
public class UserMedicalData implements Parcelable {
    private int id;
    private String title;
    private String type;
    private boolean selected;

    protected UserMedicalData(Parcel in) {
        id = in.readInt();
        title = in.readString();
        type = in.readString();
        selected = in.readByte() != 0;
    }

    public static final Creator<UserMedicalData> CREATOR = new Creator<UserMedicalData>() {
        @Override
        public UserMedicalData createFromParcel(Parcel in) {
            return new UserMedicalData(in);
        }

        @Override
        public UserMedicalData[] newArray(int size) {
            return new UserMedicalData[size];
        }
    };

    public int getId () {return id;}

    public void setId (int id) {this.id = id;}

    public String getTitle () {return title;}

    public void setTitle (String title) {this.title = title;}

    public String getType () {return type;}

    public void setType (String type) {this.type = type;}

    public boolean getSelected () {return selected;}

    public void setSelected (boolean selected) {this.selected = selected;}

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeInt(id);
        parcel.writeString(title);
        parcel.writeString(type);
        parcel.writeByte((byte) (selected ? 1 : 0));
    }
}

This solution works fine for toggling the views and Booleans , but I want to know if there is a simpler more concise method to do so. Sometimes ,using the filter on recyclerview A and toggling between data , triggers some data's booleans to turn true automatically . I have tried various ways to debug this issue and handle it but it's to no avail working for me. Please let me know if I am doing something wrong or if anything can be improved for the best .

I have tried toggling the Booleans and updating dataset using "notifyDataSetChanged" and "notifyItemRemoved" and "notifyItemAdded" methods to update the recyclerviews but during robust testing , the main recyclerview shows weird behavior that I am unable to debug or resolve.

0

There are 0 best solutions below