Android - Firebase - Send Users to Chat Room - java

Aim
Allowing the Users to access their selected Group Chat. Once the user clicks on the Group Chat name, they will be entered into that Group Chat.
Database Tree
As shown in the Database Tree, the Currently Signed In user will be shown a list of Group Chat names that have been created.
I have an Admin Account to create these Group Chats for the users.
The Android, Asia, and Europe group chats that are seen within the Database ARE NOT fixed variables. They are names. A newly Group Chat name could be "Earth".
Therefore there is no way of calling it by a variable other than calling it by the Node itself.
Screenshot of Application
List of Group Chats 2. Entering a Group Chat
Flow of Activities
GroupFragment ---> Chat Activity
GroupFragment <--- Chat Activity
Flow of Application
User--->LoginActivity--->UserActivity--->GroupFrag--->GroupChatActivity
At the (GroupFrag--->GroupChatActivity) The user must select a Group Chat name within the GroupFrag to enter the GroupChatActivity
The user must select a Group Chat name within the GroupFrag to enter the GroupChatActivity
Description
The users will be able to select a Group Chat name (from GroupFragment) and the app will bring the user into the Group Chat itself (into Chat Activity). The User will be able to go back to the GroupFragment and select another desired Group.
(Group Chat names are NOT FIXED -- They're not a node that can be called from)
Problem
I am unable to select the Group Chat names after it was prompt within the Fragment, which will then bring me to the Group Chat.
Group Fragment
#Override
public void onStart() {
super.onStart();
class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.MyHolder> {
ArrayList<String> list;
public GroupAdapter(ArrayList<String> list) {
this.list = list;
}
#Override
public GroupAdapter.MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_groups, parent, false);
return new MyHolder(view);
}
#Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.setText(list.get(position));
}
#Override
public int getItemCount() {
return list.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
public MyHolder(View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.groupChatNameTxt);
}
public void setText(String groupName) {
nameTextView.setText(groupName);
}
}
}
jGroupsDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ArrayList<String> groupChatNames = new ArrayList<>();
for (DataSnapshot child : dataSnapshot.getChildren()) {
groupChatNames.add(child.getKey());
}
GroupAdapter adapter = new GroupAdapter(groupChatNames);
jGroupChatList.setAdapter(adapter);
//I'm not sure where to write a code for userID
//final String usersID = getRef(position).getKey();
// When the user clicks on one of the group chat names, he/she will be sent to the Chat Activity
jGroupChatList.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName",groupName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
startActivity(intentUserProfile);
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Chat Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
jGroupChatName = getIntent().getExtras().get("groupChatName").toString();
jUserID = getIntent().getExtras().get("usersID").toString();
jUserName = getIntent().getExtras().get("usersName").toString();
jUserNeighbourhood = getIntent().getExtras().get("neighbourhood").toString();
jChatRoot = FirebaseDatabase.getInstance().getReference().child(jGroupChatName);
jChatToolbar = (Toolbar) findViewById(R.id.allUSersToolBar);
setSupportActionBar(jChatToolbar);
getSupportActionBar().setTitle(jGroupChatName); // Show the name of the selected group name
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Additional Comments
Online Tutorial
I have watched an Android Firebase Group Chat tutorial on youtube. The link is https://www.youtube.com/watch?v=wVCz1a3ogqk. But it does not provide some the features/ functions whic I am trying to implement.
Linked Question
Android - Firebase - Prompting Group Chat Names
Future Implementations
For future implementations, I would like to send and retrieve the messages and prompt it into the group chat for the users to view like a real group chat. But of course, I will leave that for another Question.

You can update your adapter and viewholder implementation as follows:
public class Adapter extends RecyclerView.Adapter<Adapter.MyHolder> {
Context context;
ArrayList<String> list;
public Adapter(Context context, ArrayList<String> list) {
this.context = context;
this.list = list;
}
#Override
public Adapter.MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_groups, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.setText(list.get(position));
}
#Override
public int getItemCount() {
return list.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
String groupName = list.get(getAdapterPosition());
Intent intentUserProfile = new Intent(context, MainActivity.class);
intentUserProfile.putExtra("groupChatName", groupName);
// If fixed, you should pass these values to adapter's constructor
// intentUserProfile.putExtra("neighbourhood", neighbourhood);
// intentUserProfile.putExtra("usersName", usersName);
// intentUserProfile.putExtra("usersID", usersID);
context.startActivity(intentUserProfile);
}
};
public MyHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(onClickListener);
nameTextView = (TextView) itemView.findViewById(R.id.groupChatNameTxt);
}
public void setText(String groupName) {
nameTextView.setText(groupName);
}
}
}
You also have to update this line in your GroupFragment:
GroupAdapter adapter = new GroupAdapter(getActivity(), groupChatNames);
This is another solution that you can implement inside your fragment so that you can put extras in intent (actually modified from your former question):
#Override
public void onStart() {
super.onStart();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference groupChatsRef = rootRef.child("Group Chats");
FirebaseRecyclerAdapter<String, GroupChatViewHolder> chatAdapter = new FirebaseRecyclerAdapter<String, GroupChatViewHolder>(
String.class,
R.layout.layout_groups,
GroupChatViewHolder.class,
groupChatsRef) {
protected void populateViewHolder(GroupChatViewHolder viewHolder, String model, int position) {
final String groupChatName = this.getRef(position).getKey();
viewHolder.setName(groupChatName);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName", groupChatName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
startActivity(intentUserProfile);
}
});
}
};
jGroupChatList.setAdapter(chatAdapter);
}
Note that it handles your string-string group chat entries in your DB as key-value pairs.

public class group_name_list_adapter extends RecyclerView.Adapter<group_name_list_adapter.ViewHolder> {
private List< group_name_list> listItems;
private Context context;
OnItemClickListener onItemClickListener;
public group_name_list_adapter(List<group_name_list> listItems, Context context) {
this.listItems = listItems;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.group_name_list, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
group_name_list listItem = listItems.get(position);
holder.txtTitle.setText(listItem.getTxtTitle());
holder.txtTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onGroupNameClick(position);
}
});
}
#Override
public int getItemCount() {
return listItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView txtTitle;
public ViewHolder(View itemView) {
super(itemView);
txtTitle = (TextView) itemView.findViewById(R.id.txtTitle);
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
public interface OnItemClickListener{
void onGroupNameClick(int position);
}
}
public class group_name_list {
private String txtTitle;
public group_name_list(String txtTitle) {
this.txtTitle = txtTitle;
}
public String getTxtTitle() {
return txtTitle;
}
}
public class ChatActivity implements group_name_list_adapter.OnItemClickListener
private RecyclerView recyclerGroupName;
private group_name_list_adapter groupNameAdapter;
private List<group_name_list> group_name_List;
private List<String> groupNameKeyList; //This is optional – this is used if you wanted the group chats to have the same name instead of overwriting the groupchat when creating.
Inside your Firebase call:
group_name_List.removeAll(group_name_List t);
groupNameKeyList.removeAll(groupNameKeyList);
//Depending on your firebase reference. This could just be dataSnapshot.getChildren()
for (DataSnapshot child : dataSnapshot.child("Group Chats").getChildren()){
if (!child.getKey().equals(null)){
groupNameKeyList.add(child.getKey().toString()); //Again this is optional
}
group_name_list newGroupList = child.getValue();
);
groupNameList.add(newGroupList);
}
recyclerGroupName.setAdapter(groupNameAdapter);
gLayoutAttribute = new GridLayoutManager(getActivity(), 1);
recyclerGroupName = (RecyclerView) rootView.findViewById(R.id.recyclerGroupName);
recyclerGroupName.setHasFixedSize(true);
recyclerGroupName.setLayoutManager(new LinearLayoutManager(this.getContext()));
recyclerGroupName.setLayoutManager(gLayoutAttribute);
#Override
public void onAttributeClick(int position) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName",groupName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
intent.putExtra("name", groupList.get(position).toString());
//intent.putExtra("name", groupListKeyList.get(position).toString()); this is your optional key
startActivity(intentUserProfile);
}

Try according to this
Suppose you've created 5 user's in FirebaseDatabasewith different UID's
In this step you have to get all user's from Firebase and display it in RecyclerView
In Recyclerview's adapter class in onBindViewHolder' you have to do like add and remove` users from list which you generated at the time creating group.
In this step you've to search firebaseDatabase user's Uid which is currently logged in and if your UID is matched found in any Group then you need to get the Group-name .
Happy to help you

Related

How to Properly Transfer Data from a Model Class to a RecyclerAdapter Class Using an ArrayList (Data Retrieval from Firebase Realtime Database)

I am attempting to load an undetermined number of viewHolders into a recyclerView with data retrieved from the Firebase Realtime Database. This is for a messaging component of my Android app. I am first iterating through a list of chat keys (see "Chat Keys" node below) stored in the database under the current user's userID. For each key, I access the specific associated chat (see "Chat Basics" node below). For testing purposes, I am only retrieving and setting one value type ("lastMessage"), however I intend to set multiple values per viewHolder after successful testing. I am unsure about how to correctly pass the data stored in my model class for each iteration to my onBindViewHolder in my adapter class for display in individual viewholders.
I have had success in retrieving "lastMessage" for each iteration in my fragment class, then passing a string to my adapter class for each iteration. The viewHolders did display the correct string values. Though I can do this successfully, I need to be able to pass an arrayList of data for each iteration, so that I am not limited to only passing a single value per key. Because the onBindViewHolder in the adapter class is position dependent, it is my understanding that I cannot simply pass an array list with simple strings, but should instead pass an instance (O.O.C -might not be the right word) of the model class in an arrayList to be further accessed in the adapter class.
One way or another, please help me load a set of values into an undetermined number of viewHolders for each Firebase Database chat key iteration based on the code provided below. Cheers.
Model Class:
public class MessagesList {
private String lastMessage;
//Default constructor
public MessagesList() {
}
public MessagesList(String lastMessage) {//String userName,, String profileImage) {
//this.userName = userName;
this.lastMessage = lastMessage;
//this.profileImage = profileImage;
}
public String getLastMessage() {
return lastMessage;
}
public void setLastMessage(String lastMessage) {
this.lastMessage = lastMessage;
}
}
Adapter Class:
public class TestRecyclerViewAdapter extends RecyclerView.Adapter<TestRecyclerViewAdapter.ViewHolder> {
private ItemClickListener mClickListener;
private LayoutInflater mInflater;
private ArrayList<MessagesList> mList;
//Data is passed into the constructor
public TestRecyclerViewAdapter(Context context, ArrayList<MessagesList> messagesList) {
this.mInflater = LayoutInflater.from(context);
this.mList = messagesList;
}
//Inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.standard_chat_list_layout, parent, false);
return new ViewHolder(view);
}
//Binds the data to the TextView in each row
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.chatListLastMessage.setText(mList.get(position).getLastMessage());
}
//Total number of rows
#Override
public int getItemCount() {
return 0;
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView chatListLastMessage;
ViewHolder(View itemView) {
super(itemView);
chatListLastMessage = itemView.findViewById(R.id.chatListLastMessage);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
Relevant Fragment:
public class MessagingFragment1 extends Fragment {
private DatabaseReference databaseReference;//, personalChatReference;
private RecyclerView directMessageRecycler;
private String currentUserID;
private TestRecyclerViewAdapter adapter;
private ArrayList<MessagesList> list_of_groups = new ArrayList<>();
public MessagingFragment1() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_messaging1, container, false);
currentUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
databaseReference = FirebaseDatabase.getInstance().getReference();
directMessageRecycler = rootView.findViewById(R.id.directMessageRecycler);
//directMessageRecycler.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
directMessageRecycler.setLayoutManager(linearLayoutManager);
//get a reference to the join table mentioned above
databaseReference.child("Chat Keys").child(currentUserID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
String groupId = (snapshot.getKey());
databaseReference.child("Chat Basics").child(groupId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshotInner) {
MessagesList messagesList = dataSnapshotInner.getValue(MessagesList.class);
list_of_groups.add(messagesList);
adapter = new TestRecyclerViewAdapter(getActivity(), list_of_groups);
directMessageRecycler.setAdapter(adapter);
//adapter.setClickListener();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return rootView;
}
Database Structure (x2):
Turns out I just forgot to return the correct item count
//Total number of rows
#Override
public int getItemCount() {
return mList.size();
}
and the result was a blank recyclerView. Despite the stupid reason for having posted this question, I will leave it as an example for others (like me) who've had difficulty finding a concise, full example of how to retrieve data from Firebase Database using simple key identifiers in one node to find the core data in another node.

Android: Sending a cardview from one fragment to another

I need some help for a summer project
This is my Events fragment
This is my MyList fragment
I'm using a RecyclerView+Cardview to display the Events. The idea is that the user can click the big plus on the right side of each card, and the card would be displayed in the MyList fragment. I would like to ask if it's possible to transfer a card directly from one fragment to another? Also, both fragments are contained within the same activity, which makes it a little trickier(I haven't found any available solutions).
If that is not possible, another way is to transfer the reference type object contained in the CardView to the MyList fragment. However, this is even less straightforward. This is because the button is inflated in the adapter, but there is no reference type object created here. I have seen many tutorials on using the Parcelable interface, however, I don't know how to implement it here when I'm unable to even create the object in the adapter. The reference object is created in another activity and stored in Firebase before it is read and displayed.
I'm going to attach my EventsAdapter.java and EventsItem.java and EventsFragment.java code below, but please let me know if I should include more code to describe the problem.
Thanks for reading my very long post!!
public class EventsAdapter extends RecyclerView.Adapter<EventsAdapter.EventsViewHolder> implements Filterable {
private ArrayList<EventsItem> mEventsList;
private ArrayList<EventsItem> mEventsListFull;
private EventsAdapter.OnItemClickListener mListener;
private Context mContext;
private DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.UK);
public interface OnItemClickListener {
void onItemClick(int position);
}
//the ViewHolder holds the content of the card
public static class EventsViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public ImageView mAddButton;
public TextView mTextView1;
public TextView mTextView2;
public TextView mTextView3;
public TextView mTextView4;
public TextView mTextView5;
public EventsViewHolder(Context context, View itemView, final EventsAdapter.OnItemClickListener listener) {
super(itemView);
final Context context1 = context;
mImageView = itemView.findViewById(R.id.imageView);
mAddButton = itemView.findViewById(R.id.image_add);
mTextView1 = itemView.findViewById(R.id.title);
mTextView2 = itemView.findViewById(R.id.event_description);
mTextView3 = itemView.findViewById(R.id.date);
mTextView4 = itemView.findViewById(R.id.location);
mTextView5 = itemView.findViewById(R.id.time);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
}
}
}
});
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String str1 = mTextView1.getText().toString();
String str2 = mTextView2.getText().toString();
String str3 = mTextView3.getText().toString();
String str4 = mTextView4.getText().toString();
String str5 = mTextView5.getText().toString();
Bundle bundle = new Bundle();
bundle.putString("title", str1);
bundle.putString("event description", str2);
bundle.putString("date", str3);
bundle.putString("location", str4);
bundle.putString("time", str5);
MylistFragment mlf = new MylistFragment();
mlf.setArguments(bundle);
}
});
}
}
//Constructor for EventsAdapter class. This ArrayList contains the
//complete list of items that we want to add to the View.
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
}
//inflate the items in a EventsViewHolder
#NonNull
#Override
public EventsAdapter.EventsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_item, parent, false);
EventsAdapter.EventsViewHolder evh = new EventsAdapter.EventsViewHolder(mContext, v, mListener);
return evh;
}
#Override
public void onBindViewHolder(#NonNull EventsAdapter.EventsViewHolder holder, int position) {
EventsItem currentItem = mEventsList.get(position);
holder.mImageView.setImageResource(currentItem.getProfilePicture());
holder.mTextView1.setText(currentItem.getTitle());
holder.mTextView2.setText(currentItem.getDescription());
holder.mTextView3.setText(df.format(currentItem.getDateInfo()));
holder.mTextView4.setText(currentItem.getLocationInfo());
holder.mTextView5.setText(currentItem.getTimeInfo());
}
#Override
public int getItemCount() {
return mEventsList.size();
}
public class EventsItem implements Occasion, Parcelable {
//fields removed for brevity
//constructor removed for brevity
}
public EventsItem() {
}
public EventsItem(Parcel in) {
profilePicture = in.readInt();
timeInfo = in.readString();
hourOfDay = in.readInt();
minute = in.readInt();
locationInfo = in.readString();
title = in.readString();
description = in.readString();
}
public static final Creator<EventsItem> CREATOR = new Creator<EventsItem>() {
#Override
public EventsItem createFromParcel(Parcel in) {
return new EventsItem(in);
}
#Override
public EventsItem[] newArray(int size) {
return new EventsItem[size];
}
};
//getter methods have been removed for brevity
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(profilePicture);
dest.writeString(timeInfo);
dest.writeString(locationInfo);
dest.writeString(title);
dest.writeString(description);
dest.writeString(df.format(dateInfo));
dest.writeInt(hourOfDay);
dest.writeInt(minute);
}
}
public class EventsFragment extends Fragment {
ArrayList<EventsItem> EventsItemList;
FirebaseDatabase mDatabase;
DatabaseReference mDatabaseReference;
ValueEventListener mValueEventListener;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private EventsAdapter mAdapter;
private View rootView;
public FloatingActionButton floatingActionButton;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_events, container, false);
mDatabase = FirebaseDatabase.getInstance();
mDatabaseReference = mDatabase.getReference().child("Events");
createEventsList();
buildRecyclerView();
floatingActionButton = rootView.findViewById(R.id.fab);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), EventsAdder.class);
startActivity(intent);
}
});
mValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
EventsItemList.add(snapshot.getValue(EventsItem.class));
}
EventsAdapter eventsAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setAdapter(eventsAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
mDatabaseReference.addValueEventListener(mValueEventListener);
setHasOptionsMenu(true);
Toolbar toolbar = rootView.findViewById(R.id.events_toolbar);
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
return rootView;
}
public void createEventsList() {
EventsItemList = new ArrayList<>();
}
public void buildRecyclerView() {
mRecyclerView = rootView.findViewById(R.id.recyclerview);
mLayoutManager = new LinearLayoutManager(getContext());
mAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
}
}
If you would like to see the same CardView within the MyListFragment, you could have the MyListFragment contain a RecyclerView, and reuse the same EventsAdapter and EventsViewHolder. The only difference is that rather than populating the adapter with all the children of the "Events" from your database, you would only populate it with the single Event that you want.
Also, since you have made your Event class implement parcelable, you do not need to manually create the bundle when clicking the plus button.
I am assuming you have a single Activity, and you simply want to replace the EventsFragment with the MyListFragment. Checkout the docs for replacing one fragment with another.
Step 1:
Extend your onItemClickListener to look like:
public interface OnItemClickListener {
void onItemClick(int position);
void onPlusButtonClick(int position);
}
and adjust the code in your EventsViewHolder constructor to look like this when the plus button is clicked:
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
// no need to manually create the bundle here
// you already have all the information you need
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onPlusButtonClick(position);
}
}
}
});
Step 2:
Implement our new method onPlusButtonClick. As per our discussion in the comments, it seems you do not implement this interface anywhere. You can implement it inside the constructor to your EventsAdapter:
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
mListener = new OnItemClickListener() {
#Override
public void onItemClick() {
// handle clicking the entire view holder
// NOTE: inside your EventsViewHolder, it looks like you call this method on the entire itemView. This could 'swallow' the click on the plus button. You may need to adjust your code to handle this.
}
#Override
public void onPlusButtonClick(int position) {
MyListFragment myListFragment = new MyListFragment();
Event event = mEventsList.get(position);
Bundle bundle = new Bundle();
bundle.putExtra("event", event); // this will work due to implementing parcelable
myListFragment.setArguments(bundle);
// use mContext since im assuming we areinside adapter
// if in an Activity, no need to use context to get the fragment manager
FragmentTransaction transaction = mContext.getSupportFragmentManager().beginTransaction();
// Replace the EventsFragment with the MyListFragment
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, myListFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Step 3:
Inside your MyListFragments onCreateView() method:
#Override
public View onCreateView (
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState
) {
Bundle bundle = getArguments();
Event event = bundle.getExtra("event"); // again, will work due to implementing parcelable
// from here you should bind to a recycler view, and you can even reuse your adapter like so:
List<EventsItem> singleEventList = new List<EventsItem>();
singleEventList.add(event);
EventsAdapter adapter = new EventsAdapter(getActivity(), singleEventList);
// be sure to inflate and return your view here...
}
and you should be good to go!
I have left out bits of code here and there for simplicity.. but I hope this is understandable.
As a side note.. in your firebase database listener, it is bad practice to create a new EventsAdapter every single time your data is updated. Instead, you should update the data in the adapter with the new values. Do this by creating a public method inside the adapter such as replaceEvents(List<EventsItem> newEvents), and inside, replace mEventsList with the new events, then call notifyDataSetChanged().

Android: Passing variables that allows recyclerview to be populated by specific strings

I'm trying to create a code saying "Where the username that is logged in matches the username of a created recipe, only show these database entries in the recyclerview on my MyRecipes.java activity". I'm having trouble working out where to put this potential statement. Looking at my code, where would you put that statement, if or otherwise?
The userLoggedIn and loggedUser is the variable for the currently logged in user.
The thisUser is what I've set as the users pulled from the database when the recyclerview is populating in the recyclerview.java class.
Any help would be greatly appreciated!
RecyclerView.java class
private static String thisUser;
String userLoggedIn = HomeActivity.getUserLogged();
private Context mContext;
private RecipesAdapter mRecipeAdapter;
public void setConfig (RecyclerView recyclerView, Context context, List<Recipes> recipes, List<String> keys){
mContext = context;
mRecipeAdapter = new RecipesAdapter(recipes, keys);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(mRecipeAdapter);
}
class RecipeItemView extends RecyclerView.ViewHolder{
private TextView mTitle;
private TextView mIngredients;
private TextView mMethod;
private TextView mUser;
private String key;
public RecipeItemView(ViewGroup parent){
super(LayoutInflater.from(mContext).inflate(R.layout.recipe_list_item, parent,false));
mTitle = (TextView) itemView.findViewById(R.id.tvTitle);
mMethod = (TextView) itemView.findViewById(R.id.tvMethod);
mIngredients = (TextView) itemView.findViewById(R.id.tvIngredients);
mUser = (TextView) itemView.findViewById(R.id.tvUser);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, RecipeDetails.class);
intent.putExtra("key", key);
intent.putExtra("title", mTitle.getText().toString());
intent.putExtra("ingredients", mIngredients.getText().toString());
intent.putExtra("method", mMethod.getText().toString());
mContext.startActivity(intent);
}
});
}
public void bind(Recipes recipes, String key) {
mTitle.setText(recipes.getTitle());
mIngredients.setText(recipes.getIngredients());
mMethod.setText(recipes.getMethod());
mUser.setText(recipes.getCreatedUser());
thisUser = mUser.getText().toString().trim();
this.key = key;
}
}
public static String getUserLoggedIn(){
return thisUser;
}
class RecipesAdapter extends RecyclerView.Adapter<RecipeItemView> {
private List<Recipes> mRecipeList;
private List<String> mKeys;
public RecipesAdapter(List<Recipes> mRecipeList, List<String> mKeys) {
this.mRecipeList = mRecipeList;
this.mKeys = mKeys;
}
#NonNull
#Override
public RecipeItemView onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new RecipeItemView(parent);
}
#Override
public void onBindViewHolder(#NonNull RecipeItemView holder, int position) {
holder.bind(mRecipeList.get(position), mKeys.get(position));
}
#Override
public int getItemCount() {
return mRecipeList.size();
}
}
}
MyRecipes.java (Where the recycler view populates and shows all the recipes)
String loggedUser = HomeActivity.getUserLogged();
String thisUser = RecyclerViewConfig.getUserLoggedIn();
Button addRecipes;
private RecyclerView mRecyclerView;
private String passedUsername;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_recipes);
passedUsername = getIntent().getStringExtra("loggedUsername1");
mRecyclerView = (RecyclerView) findViewById(R.id.rvRecipes);
new FirebaseDatabaseHelper().readRecipes(new FirebaseDatabaseHelper.DataStatus() {
#Override
public void DataIsLoaded(List<Recipes> recipes, List<String> keys) {
new RecyclerViewConfig().setConfig(mRecyclerView, MyRecipesActivity.this, recipes, keys);
}
#Override
public void DataIsInserted() {
}
#Override
public void DataIsUpdated() {
}
#Override
public void DataIsDeleted() {
}
});
addRecipes = findViewById(R.id.btnAddNewRecipe);
addRecipes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent addrecipe = new Intent(MyRecipesActivity.this, AddRecipes.class);
addrecipe.putExtra("loggedUsername2", passedUsername);
startActivity(addrecipe);
}
});
}
}
If i understand correctly, you need to show the recipes to the user only if he/she is the one who created it? Assuming that, below change in the code will do the trick.
Change your bind() method as follows.
public void bind(Recipes recipes, String key) {
thisUser = mUser.getText().toString().trim();
if(thisUser.equals(recipes.getCreatedUser)) {
mTitle.setText(recipes.getTitle());
mIngredients.setText(recipes.getIngredients());
mMethod.setText(recipes.getMethod());
mUser.setText(recipes.getCreatedUser());
this.key = key;
}
}
Though that is a naive approach, a better approach would be to filter the recipes list with created user when you load data from Firebase with readRecipes() method itself. To do that a query can be used as below(the exact query below might not work for you depending on your DB structure. Change it as needed)
Query query = reference.child("Recipes").orderByChild("userCreated").equalTo(thisUser);

How to show an onClick message when clicking on an item of my RecyclerView list?

I am actually working on a group project and I want to develop a functionnality for our application. My goal is to have a list of several items with their images and when I click on an Item of that list I want to have a text pop in the midle of the screen related to that particular item. I'm afraid I might be using the wrong technical Tools to do so. I am actually using a csv file for the list details, an adapter and a viewHolder for the list. Since I have no idea on what is wrong and what to do I link a big part of my code so you can check how I did until now. I can also give you my xml files if you need to check them out, a really big thanks in advance to all the answers and time spent on my problem
I already managed to have my list of items with the title and the picture (text from csv file) of each list item but I'm stuck on how to show a specific text for each ViewHolder.
this is my Adapter
public class Adapter extends RecyclerView.Adapter<ViewHolder> {
List<Departement> list;
Activity activity;
public Adapter(List<Departement> list, Activity activity) {
this.list = list;
this.activity = activity;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int itemType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.departement,viewGroup,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
Departement departement = list.get(position);
viewHolder.bind(departement, activity);
}
#Override
public int getItemCount() {
return list.size();
}
}
my ViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView textViewView;
private ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
textViewView = (TextView) itemView.findViewById(R.id.text);
imageView = (ImageView) itemView.findViewById(R.id.image);
}
public void bind(Departement departement, Activity activity){
textViewView.setText(departement.getText());
String uri = departement.getImageUrl();
int imageResource = activity.getResources().getIdentifier(uri, null, activity.getPackageName());
Drawable res = activity.getResources().getDrawable(imageResource);
imageView.setImageDrawable(res);
}
}
each item of the list is a Departement
public class Departement {
private String text;
private String imageUrl;
public Departement(String text, String imageUrl) {
this.text = text;
this.imageUrl = imageUrl;
}
public String getText() {
return text;
}
public String getImageUrl() {
return imageUrl;
}
public void setText(String text) {
this.text = text;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
and finally my fragment
public class FragmentEspecesProches extends Fragment {
public final static char SEPARATOR=',';
private RecyclerView recyclerView;
private List<Departement> departementsList = new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = inflater.inflate(R.layout.fragment_especes_proches, container, false);
ajouterDepartements();
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new GridLayoutManager(this,2));
recyclerView.setAdapter(new Adapter(departementsList, getActivity()));
return view;
}
private void ajouterDepartements() {
ArrayList<String> lines = new ArrayList<>();
ArrayList<String[]> data = new ArrayList<>();
String sep = new Character(SEPARATOR).toString();
lines = UtilitaireResultat.readFile(getActivity().getResources().openRawResource(R.raw.departement));
for(String line : lines){
String[] oneData = line.split(sep);
data.add(oneData);
}
for(int i=0 ; i<data.size() ; i++){
String[] tabStr = data.get(i);
departementsList.add( new Departement( tabStr[2]+" - "+tabStr[3] ,"#drawable/"+tabStr[5] ));
}
}
}
you can implement item click listener like this
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView tvName;
public TextView tvHometown;
private Context context;
public ViewHolder(Context context, View itemView) {
super(itemView);
this.tvName = (TextView) itemView.findViewById(R.id.tvName);
this.tvHometown = (TextView) itemView.findViewById(R.id.tvHometown);
// Store the context
this.context = context;
// Attach a click listener to the entire row view
itemView.setOnClickListener(this);
}
// Handles the row being being clicked
#Override
public void onClick(View view) {
int position = getAdapterPosition(); // gets item position
// if (position != RecyclerView.NO_POSITION) { // Check if an item was deleted, but the user clicked it before the UI removed it
User user = users.get(position);
// We can access the data within the views
Toast.makeText(context, tvName.getText(), Toast.LENGTH_SHORT).show();
// }
}
}
Use onBindViewHolder to handle any interaction on your list items
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
Departement departement = list.get(position);
viewHolder.bind(departement, activity);
viewHolder.itemView.setOnClickListener(//your action//);
}
ItemView is the whole item; you can access your textviews or imageviews as you use it on your bind method,
You can use your bind method to apply listeners.
Handle on click of the item inside your ViewHolder constructor
like ,
public ViewHolder(View itemView) {
super(itemView);
textViewView = (TextView) itemView.findViewById(R.id.text);
imageView = (ImageView) itemView.findViewById(R.id.image);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position=getAdapterPosition();
Toast.makeText(context, list.get(position).getText(), Toast.LENGTH_SHORT).show();
}
});
}
Create your onClickListner interface as
interface RecylerViewItemClickListner
{
void onItemClick(Department item)
}
set the listner in Adapter class
private final RecylerViewItemClickListner mOnClickListener;
public Adapter(List<Departement> list, Activity activity) {
this.list = list;
this.activity = activity;
this.mOnClickListener = activity;
}
Now in ViewHolder class
public void bind(final Departement item, final mOnClickListener listener) {
itemView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
mOnClickListener.onItemClick(item);
}
});
}
and change onBindViewHolder as below
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(items.get(position), mOnClickListener);
}
Override onItemClick(Department item) in activity
#override
onItemClick(Department item)
{
//show toast here...
}
implement OnClickListener in your ViewHolder class
public class ViewHolder extends RecyclerView.ViewHolder implements
View.OnClickListener
{
#Override
public void onClick(View v)
{
//do action
}
}
Implement below method in your ViewHolder class.
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final User currentItem = users.get(getAdapterPosition());
Toast.makeText(mContext,currentItem.getText()+" is selected!",Toast.LENGTH_SHORT).show();
}
});

Unable to filter query with multiple clauses using Firebase Realtime Database

I'm using Firebase Realtime Database with Firebase UI, however i'm not being able to search with multiple clauses.
What i need is to take the Users that do not have an specific id. As i'm already filtering them by City i need to filter these ones with specific id.
I've been trying to solve it in many ways, however none of them has come to success.
This is my Database
I cant take and render the card with the user with that username.
public class SearchFragment extends android.support.v4.app.Fragment {
private EditText mSearchField;
private ImageButton mSearchBtn;
private RecyclerView mResultList;
private DatabaseReference mUserDatabase;
public static SearchFragment newInstance() { return new SearchFragment(); }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_search, container, false);
mSearchField = view.findViewById(R.id.search_field);
mSearchBtn = view.findViewById(R.id.search_btn);
mResultList = view.findViewById(R.id.result_list);
mResultList.setHasFixedSize(true);
mResultList.setLayoutManager(new LinearLayoutManager(mResultList.getContext()));
mSearchBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String searchText = mSearchField.getText().toString();
firebaseUserSearch(searchText);
mSearchField.setText("");
}
});
mUserDatabase = FirebaseDatabase.getInstance().getReference("usuarios");
return view;
}
public void firebaseUserSearch(String searchText) {
Toast.makeText(getContext(), "Buscando usuários", Toast.LENGTH_LONG).show();
String searchTextLower = searchText.toLowerCase();
final Query firebaseSearchQuery = mUserDatabase.orderByChild("city").startAt(searchTextLower).endAt(searchTextLower + "\uf8ff");
firebaseSearchQuery.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
GenericTypeIndicator<Map<String, String>> genericTypeIndicator = new GenericTypeIndicator<Map<String, String>>() {};
Map<String, String> map = dataSnapshot.getValue(genericTypeIndicator );
String username = map.get("username").toString();
Log.d("oi", username);
Log.d("olar", UserDetails.username);
if(username != UserDetails.username) {
final FirebaseRecyclerOptions<User> options =
new FirebaseRecyclerOptions.Builder<User>()
.setQuery(firebaseSearchQuery, User.class)
.build();
bindAndBuildFirebaseUi(options);
}
}
public void bindAndBuildFirebaseUi(FirebaseRecyclerOptions options) {
final FirebaseRecyclerAdapter<User, UsersViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<User, UsersViewHolder>(options) {
#Override
public UsersViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_layout, parent, false);
return new UsersViewHolder(v);
}
#Override
protected void onBindViewHolder(final UsersViewHolder holder, int position, final User model) {
holder.bind(model);
Log.d("SearchFragment", "Binded the model");
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UserDetails.chatWithId = model.getUsername();
UserDetails.chatWith = model.getName();
startActivity(new Intent(getContext(), Chat.class));
}
});
}
};
firebaseRecyclerAdapter.startListening();
mResultList.setAdapter(firebaseRecyclerAdapter);
}
}
As you can see i even tried to filter them throught the database again, howeever, Firebase ui is taking the filter from options which is the first query filtering the users by city.
Does anyone have any idea how to take avoid rendering the users with an specific id???
And i also know that Firebase does not allow to use more than one orderBy.
The Firebase RTDB doesn't support multiple where clauses unfortunately. However, if you denormalize your data properly, you can use one query to link to another ref in the database and effectively filter data in that way. Take a look at the docs: https://github.com/firebase/FirebaseUI-Android/blob/master/database/README.md#using-firebaseui-with-indexed-data.
As a side note, you really shouldn't be using the RTDB to store actual data as it won't scale. It's designed for low latency real-time updates for multiplayer stuff or a ticketing app etc. Instead, I'd recommend looking into Firestore, especially if this is a new app.
Here's the hack I mentioned in my comment below:
public class MyAdapter extends FirebaseRecyclerAdapter {
private static final int TYPE_NORMAL = 0;
private static final int TYPE_HIDDEN = 1;
private final View mEmpty = new View(getContext());
public MyAdapter(#NonNull FirestoreRecyclerOptions options) {
super(options);
mEmpty.setVisibility(View.GONE);
}
#Override
public int getItemViewType(int position) {
if (getItem(position).username.equals(UserDetails.username)) {
return TYPE_HIDDEN;
} else {
return TYPE_NORMAL;
}
}
#Override
public UsersViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HIDDEN) {
return new UsersViewHolder(mEmpty);
}
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_layout, parent, false);
return new UsersViewHolder(v);
}
#Override
protected void onBindViewHolder(final UsersViewHolder holder, int position, final User model) {
if (getItemViewType(position) == TYPE_HIDDEN) return;
holder.bind(model);
Log.d("SearchFragment", "Binded the model");
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UserDetails.chatWithId = model.getUsername();
UserDetails.chatWith = model.getName();
startActivity(new Intent(getContext(), Chat.class));
}
});
}
}

Categories

Resources