This is the Part 14 of “Build a Social Media App on Android Studio” tutorial, and we are going to cover the following functionalities in this article:
- We are going to Create a Layout for chat & Send Messages in Chat.
- A user can send either a Message or an Image.
- A user can send an image either using a camera or gallery.
- Firstly a request for permission will be asked to send an image using a gallery or after clicking the image using the camera.
- If permission is given then the user can send the image, or it will again request for asking permission.
Step By Step Implementation
Step 1: Create two new layout resource files and name them row_chat_left and row_chat_right
Working with the row_chat_left.xml file. The received message will be on the left side. Similarly, Working with the row_chat_right.xml file. The message sends to the user will be on the right side. Below is the code for the row_chat_left.xml file and row_chat_right.xml file.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout android:id = "@+id/msglayout" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:orientation = "vertical" android:padding = "10dp" > < LinearLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:orientation = "horizontal" > < de.hdodenhof.circleimageview.CircleImageView android:id = "@+id/profilec" android:layout_width = "50dp" android:layout_height = "50dp" android:src = "@drawable/profile_image" app:civ_border_color = "@null" /> < TextView android:id = "@+id/msgc" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_weight = "1" android:background = "@drawable/bg_receiver" android:padding = "15dp" android:text = "His Message" android:textColor = "@color/colorBlack" android:textSize = "16sp" android:visibility = "gone" /> < ImageView android:id = "@+id/images" android:layout_width = "200dp" android:layout_height = "200dp" android:adjustViewBounds = "true" android:background = "@drawable/bg_receiver" android:padding = "15dp" android:scaleType = "fitCenter" android:src = "@drawable/ic_images" /> < TextView android:id = "@+id/timetv" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "02/01/1990 06:19PM" android:textColor = "@color/colorBlack" android:textSize = "12sp" /> </ LinearLayout > < TextView android:id = "@+id/isSeen" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:gravity = "end" android:text = "Delivered" android:textAlignment = "textEnd" android:visibility = "gone" /> </ LinearLayout > |
XML
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout android:id = "@+id/msglayout" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:orientation = "vertical" android:padding = "10dp" > < RelativeLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:orientation = "horizontal" > < de.hdodenhof.circleimageview.CircleImageView android:id = "@+id/profilec" android:layout_width = "50dp" android:layout_height = "50dp" android:src = "@drawable/profile_image" android:visibility = "gone" app:civ_border_color = "@null" /> < TextView android:id = "@+id/timetv" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "02/01/1990 06:19PM" android:textColor = "@color/colorBlack" android:textSize = "12sp" /> < TextView android:id = "@+id/msgc" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_alignParentEnd = "true" android:layout_toEndOf = "@id/timetv" android:background = "@drawable/bg_sender" android:padding = "15dp" android:text = "His Message" android:textColor = "@color/colorBlack" android:textSize = "16sp" /> < ImageView android:id = "@+id/images" android:layout_width = "200dp" android:layout_height = "200dp" android:layout_alignParentEnd = "true" android:adjustViewBounds = "true" android:background = "@drawable/bg_sender" android:padding = "15dp" android:scaleType = "fitCenter" android:src = "@drawable/ic_images" /> </ RelativeLayout > < TextView android:id = "@+id/isSeen" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:gravity = "end" android:text = "Delivered" android:textAlignment = "textEnd" /> </ LinearLayout > |
Step 2: Working with the activity_chat.xml file
Here In the RecyclerView, we will be showing all the messages. In the TextView user will type the message and using the send button user will send the message. Below is the code for the activity_chat.xml file.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < RelativeLayout android:layout_width = "match_parent" android:layout_height = "match_parent" tools:context = ".ChatActivity" > < androidx.appcompat.widget.Toolbar android:id = "@+id/toolbar" android:layout_width = "match_parent" android:layout_height = "?android:attr/actionBarSize" android:background = "@color/colorPrimaryDark" android:theme = "@style/ThemeOverlay.AppCompat.Dark.ActionBar" > < LinearLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:orientation = "horizontal" > < de.hdodenhof.circleimageview.CircleImageView android:id = "@+id/profiletv" android:layout_width = "35dp" android:layout_height = "35dp" android:scaleType = "centerCrop" android:src = "@drawable/profile_image" app:civ_circle_background_color = "@color/colorPrimaryDark" /> < LinearLayout android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginStart = "20dp" android:layout_marginLeft = "20dp" android:layout_weight = "1" android:gravity = "center" android:orientation = "vertical" > < TextView android:id = "@+id/nameptv" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_weight = "1" android:text = "HisName" android:textColor = "@color/colorWhite" android:textSize = "18sp" android:textStyle = "bold" /> < TextView android:id = "@+id/onlinetv" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:text = "Online" android:textColor = "@color/colorWhite" android:textStyle = "bold" /> </ LinearLayout > < ImageView android:id = "@+id/block" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_gravity = "center_vertical" android:layout_marginEnd = "5dp" android:src = "@drawable/ic_unblock" /> </ LinearLayout > </ androidx.appcompat.widget.Toolbar > < androidx.recyclerview.widget.RecyclerView android:id = "@+id/chatrecycle" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_above = "@id/chatlayout" android:layout_below = "@id/toolbar" /> < LinearLayout android:id = "@+id/chatlayout" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_alignParentBottom = "true" android:background = "@color/colorWhite" android:gravity = "center" android:orientation = "horizontal" > < ImageButton android:id = "@+id/attachbtn" android:layout_width = "50dp" android:layout_height = "50dp" android:background = "@null" android:src = "@drawable/ic_iattach" /> < EditText android:id = "@+id/messaget" android:layout_width = "0dp" android:layout_height = "wrap_content" android:layout_weight = "1" android:background = "@null" android:hint = "Start Typing" android:inputType = "textCapSentences|textMultiLine" android:padding = "15dp" /> < ImageButton android:id = "@+id/sendmsg" android:layout_width = "40dp" android:layout_height = "40dp" android:background = "@null" android:src = "@drawable/send_message" /> </ LinearLayout > </ RelativeLayout > |
Step 3: Working with the row_chatlist.xml file
Create another layout resource file and name the file as row_chatlist. Below is the code for the row_chatlist.xml file.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < androidx.cardview.widget.CardView android:layout_width = "match_parent" android:layout_height = "wrap_content" android:orientation = "vertical" app:contentPadding = "3dp" > < RelativeLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" > < de.hdodenhof.circleimageview.CircleImageView android:id = "@+id/profileimage" android:layout_width = "70dp" android:layout_height = "70dp" android:src = "@drawable/profile_image" /> < de.hdodenhof.circleimageview.CircleImageView android:id = "@+id/onlinestatus" android:layout_width = "25dp" android:layout_height = "25dp" /> < TextView android:id = "@+id/nameonline" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginStart = "4dp" android:layout_toEndOf = "@id/profileimage" android:layout_toRightOf = "@id/profileimage" android:text = "His Name" android:textColor = "@color/colorBlack" android:textSize = "18sp" /> < TextView android:id = "@+id/lastmessge" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_below = "@id/nameonline" android:layout_marginStart = "4dp" android:layout_toEndOf = "@id/profileimage" android:layout_toRightOf = "@id/profileimage" android:maxLines = "2" android:text = "Last Message" android:textColor = "@color/colorBlack" /> < ImageView android:id = "@+id/blocking" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_alignParentEnd = "true" android:layout_gravity = "center_vertical" android:src = "@drawable/ic_unblock" /> < ImageView android:id = "@+id/seen" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_below = "@id/blocking" android:layout_alignParentEnd = "true" android:layout_gravity = "center_vertical" android:src = "@drawable/ic_unblock" /> </ RelativeLayout > </ androidx.cardview.widget.CardView > |
Step 4: Working with the ModelChat.java file
Created this class to initialize the key so that we can retrieve the value of the key later.
Java
package com.example.socialmediaapp; public class ModelChat { String message; public String getMessage() { return message; } public void setMessage(String message) { this .message = message; } public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this .receiver = receiver; } public String getSender() { return sender; } public void setSender(String sender) { this .sender = sender; } public String getTimestamp() { return timestamp; } public void setTimestamp(String timestamp) { this .timestamp = timestamp; } public boolean isDilihat() { return dilihat; } public void setDilihat( boolean dilihat) { this .dilihat = dilihat; } String receiver; public ModelChat() { } String sender; public String getType() { return type; } public void setType(String type) { this .type = type; } public ModelChat(String message, String receiver, String sender, String type, String timestamp, boolean dilihat) { this .message = message; this .receiver = receiver; this .sender = sender; this .type = type; this .timestamp = timestamp; this .dilihat = dilihat; } String type; String timestamp; boolean dilihat; } |
Step 5: Working with the AdpaterChat.java file
Create a new java class and name the class as AdpaterChat. Below is the code for the AdpaterChat.java file.
Java
package com.example.socialmediaapp; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.Query; import com.google.firebase.database.ValueEventListener; import java.util.Calendar; import java.util.List; import java.util.Locale; import de.hdodenhof.circleimageview.CircleImageView; public class AdapterChat extends RecyclerView.Adapter<com.example.socialmediaapp.AdapterChat.Myholder> { private static final int MSG_TYPE_LEFT = 0 ; private static final int MSG_TYPR_RIGHT = 1 ; Context context; List<ModelChat> list; String imageurl; FirebaseUser firebaseUser; public AdapterChat(Context context, List<ModelChat> list, String imageurl) { this .context = context; this .list = list; this .imageurl = imageurl; } @NonNull @Override public Myholder onCreateViewHolder( @NonNull ViewGroup parent, int viewType) { if (viewType == MSG_TYPE_LEFT) { View view = LayoutInflater.from(context).inflate(R.layout.row_chat_left, parent, false ); return new Myholder(view); } else { View view = LayoutInflater.from(context).inflate(R.layout.row_chat_right, parent, false ); return new Myholder(view); } } @Override public void onBindViewHolder( @NonNull Myholder holder, final int position) { String message = list.get(position).getMessage(); String timeStamp = list.get(position).getTimestamp(); String type = list.get(position).getType(); Calendar calendar = Calendar.getInstance(Locale.ENGLISH); calendar.setTimeInMillis(Long.parseLong(timeStamp)); String timedate = DateFormat.format( "dd/MM/yyyy hh:mm aa" , calendar).toString(); holder.message.setText(message); holder.time.setText(timedate); try { Glide.with(context).load(imageurl).into(holder.image); } catch (Exception e) { } if (type.equals( "text" )) { holder.message.setVisibility(View.VISIBLE); holder.mimage.setVisibility(View.GONE); holder.message.setText(message); } else { holder.message.setVisibility(View.GONE); holder.mimage.setVisibility(View.VISIBLE); Glide.with(context).load(message).into(holder.mimage); } holder.msglayput.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle( "Delete Message" ); builder.setMessage( "Are You Sure To Delete This Message" ); builder.setPositiveButton( "Delete" , new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { deleteMsg(position); } }); builder.setNegativeButton( "Cancel" , new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } }); } private void deleteMsg( int position) { final String myuid = FirebaseAuth.getInstance().getCurrentUser().getUid(); String msgtimestmp = list.get(position).getTimestamp(); DatabaseReference dbref = FirebaseDatabase.getInstance().getReference().child( "Chats" ); Query query = dbref.orderByChild( "timestamp" ).equalTo(msgtimestmp); query.addListenerForSingleValueEvent( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) { if (dataSnapshot1.child( "sender" ).getValue().equals(myuid)) { // any two of below can be used dataSnapshot1.getRef().removeValue(); /* HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put("message", "This Message Was Deleted"); dataSnapshot1.getRef().updateChildren(hashMap); Toast.makeText(context,"Message Deleted.....",Toast.LENGTH_LONG).show(); */ } else { Toast.makeText(context, "you can delete only your msg...." , Toast.LENGTH_LONG).show(); } } } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); } @Override public int getItemCount() { return list.size(); } @Override public int getItemViewType( int position) { firebaseUser = FirebaseAuth.getInstance().getCurrentUser(); if (list.get(position).getSender().equals(firebaseUser.getUid())) { return MSG_TYPR_RIGHT; } else { return MSG_TYPE_LEFT; } } class Myholder extends RecyclerView.ViewHolder { CircleImageView image; ImageView mimage; TextView message, time, isSee; LinearLayout msglayput; public Myholder( @NonNull View itemView) { super (itemView); image = itemView.findViewById(R.id.profilec); message = itemView.findViewById(R.id.msgc); time = itemView.findViewById(R.id.timetv); isSee = itemView.findViewById(R.id.isSeen); msglayput = itemView.findViewById(R.id.msglayout); mimage = itemView.findViewById(R.id.images); } } } |
Step 6: Working with the ChatActivity.java file
We are Reading the user message from “Chats” Node in Firebase. Every time data changes this data will change accordingly
chatList=new ArrayList<>(); DatabaseReference dbref= FirebaseDatabase.getInstance().getReference().child("Chats");
Loading the Data setting data value using adapter chat
ModelChat modelChat=dataSnapshot1.getValue(ModelChat.class); if(modelChat.getSender().equals(myuid)&& modelChat.getReceiver().equals(uid)|| modelChat.getReceiver().equals(myuid) && modelChat.getSender().equals(uid)){ chatList.add(modelChat);//add the chat in chatlist } adapterChat=new AdapterChat(ChatActivity.this,chatList,image); adapterChat.notifyDataSetChanged(); recyclerView.setAdapter(adapterChat);
Sending Messages in Chat Reference node value. Here is how we are saving data in the Firebase Realtime database
DatabaseReference databaseReference= FirebaseDatabase.getInstance().getReference(); String timestamp=String.valueOf(System.currentTimeMillis()); HashMap<String,Object> hashMap=new HashMap<>(); hashMap.put("sender",myuid); hashMap.put("receiver",uid); hashMap.put("message",message); hashMap.put("timestamp",timestamp); hashMap.put("dilihat",false); hashMap.put("type","text"); databaseReference.child("Chats").push().setValue(hashMap);
Below is the code for the ChatActivity.java file.
Java
package com.example.socialmediaapp; import android.Manifest; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.ContentValues; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.text.TextUtils; import android.text.format.DateFormat; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.Task; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.Query; import com.google.firebase.database.ValueEventListener; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; import com.google.firebase.storage.UploadTask; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; public class ChatActivity extends AppCompatActivity { Toolbar toolbar; RecyclerView recyclerView; ImageView profile, block; TextView name, userstatus; EditText msg; ImageButton send, attach; FirebaseAuth firebaseAuth; String uid, myuid, image; ValueEventListener valueEventListener; List<ModelChat> chatList; AdapterChat adapterChat; private static final int IMAGEPICK_GALLERY_REQUEST = 300 ; private static final int IMAGE_PICKCAMERA_REQUEST = 400 ; private static final int CAMERA_REQUEST = 100 ; private static final int STORAGE_REQUEST = 200 ; String cameraPermission[]; String storagePermission[]; Uri imageuri = null ; FirebaseDatabase firebaseDatabase; DatabaseReference users; boolean notify = false ; boolean isBlocked = false ; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_chat); firebaseAuth = FirebaseAuth.getInstance(); // initialise the text views and layouts profile = findViewById(R.id.profiletv); name = findViewById(R.id.nameptv); userstatus = findViewById(R.id.onlinetv); msg = findViewById(R.id.messaget); send = findViewById(R.id.sendmsg); attach = findViewById(R.id.attachbtn); block = findViewById(R.id.block); LinearLayoutManager linearLayoutManager = new LinearLayoutManager( this ); linearLayoutManager.setStackFromEnd( true ); recyclerView = findViewById(R.id.chatrecycle); recyclerView.setHasFixedSize( true ); recyclerView.setLayoutManager(linearLayoutManager); uid = getIntent().getStringExtra( "uid" ); // getting uid of another user using intent firebaseDatabase = FirebaseDatabase.getInstance(); // initialising permissions cameraPermission = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}; storagePermission = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}; checkUserStatus(); users = firebaseDatabase.getReference( "Users" ); attach.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { showImagePicDialog(); } }); send.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { notify = true ; String message = msg.getText().toString().trim(); if (TextUtils.isEmpty(message)) { //if empty Toast.makeText(ChatActivity. this , "Please Write Something Here" , Toast.LENGTH_LONG).show(); } else { sendmessage(message); } msg.setText( "" ); } }); Query userquery = users.orderByChild( "uid" ).equalTo(uid); userquery.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { // retrieve user data for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) { String nameh = "" + dataSnapshot1.child( "name" ).getValue(); image = "" + dataSnapshot1.child( "image" ).getValue(); String onlinestatus = "" + dataSnapshot1.child( "onlineStatus" ).getValue(); String typingto = "" + dataSnapshot1.child( "typingTo" ).getValue(); if (typingto.equals(myuid)) { // if user is typing to my chat userstatus.setText( "Typing...." ); // type status as typing } else { if (onlinestatus.equals( "online" )) { userstatus.setText(onlinestatus); } else { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(Long.parseLong(onlinestatus)); String timedate = DateFormat.format( "dd/MM/yyyy hh:mm aa" , calendar).toString(); userstatus.setText( "Last Seen:" + timedate); } } name.setText(nameh); try { Glide.with(ChatActivity. this ).load(image).placeholder(R.drawable.profile_image).into(profile); } catch (Exception e) { } } } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); readMessages(); } @Override protected void onPause() { super .onPause(); String timestamp = String.valueOf(System.currentTimeMillis()); checkOnlineStatus(timestamp); checkTypingStatus( "noOne" ); } @Override protected void onResume() { checkOnlineStatus( "online" ); super .onResume(); } @Override public boolean onSupportNavigateUp() { onBackPressed(); return super .onSupportNavigateUp(); } private void checkOnlineStatus(String status) { // check online status DatabaseReference dbref = FirebaseDatabase.getInstance().getReference( "Users" ).child(myuid); HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put( "onlineStatus" , status); dbref.updateChildren(hashMap); } private void checkTypingStatus(String typing) { DatabaseReference dbref = FirebaseDatabase.getInstance().getReference( "Users" ).child(myuid); HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put( "typingTo" , typing); dbref.updateChildren(hashMap); } @Override protected void onStart() { checkUserStatus(); checkOnlineStatus( "online" ); super .onStart(); } private void readMessages() { // show message after retrieving data chatList = new ArrayList<>(); DatabaseReference dbref = FirebaseDatabase.getInstance().getReference().child( "Chats" ); dbref.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { chatList.clear(); for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) { ModelChat modelChat = dataSnapshot1.getValue(ModelChat. class ); if (modelChat.getSender().equals(myuid) && modelChat.getReceiver().equals(uid) || modelChat.getReceiver().equals(myuid) && modelChat.getSender().equals(uid)) { chatList.add(modelChat); // add the chat in chatlist } adapterChat = new AdapterChat(ChatActivity. this , chatList, image); adapterChat.notifyDataSetChanged(); recyclerView.setAdapter(adapterChat); } } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); } private void showImagePicDialog() { String options[] = { "Camera" , "Gallery" }; AlertDialog.Builder builder = new AlertDialog.Builder(ChatActivity. this ); builder.setTitle( "Pick Image From" ); builder.setItems(options, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == 0 ) { if (!checkCameraPermission()) { // if permission is not given requestCameraPermission(); // request for permission } else { pickFromCamera(); // if already access granted then click } } else if (which == 1 ) { if (!checkStoragePermission()) { // if permission is not given requestStoragePermission(); // request for permission } else { pickFromGallery(); // if already access granted then pick } } } }); builder.create().show(); } public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int [] grantResults) { // request for permission if not given switch (requestCode) { case CAMERA_REQUEST: { if (grantResults.length > 0 ) { boolean camera_accepted = grantResults[ 0 ] == PackageManager.PERMISSION_GRANTED; boolean writeStorageaccepted = grantResults[ 1 ] == PackageManager.PERMISSION_GRANTED; if (camera_accepted && writeStorageaccepted) { pickFromCamera(); // if access granted then click } else { Toast.makeText( this , "Please Enable Camera and Storage Permissions" , Toast.LENGTH_LONG).show(); } } } break ; case STORAGE_REQUEST: { if (grantResults.length > 0 ) { boolean writeStorageaccepted = grantResults[ 0 ] == PackageManager.PERMISSION_GRANTED; if (writeStorageaccepted) { pickFromGallery(); // if access granted then pick } else { Toast.makeText( this , "Please Enable Storage Permissions" , Toast.LENGTH_LONG).show(); } } } break ; } } @Override public void onActivityResult( int requestCode, int resultCode, @Nullable Intent data) { if (resultCode == RESULT_OK) { if (requestCode == IMAGEPICK_GALLERY_REQUEST) { imageuri = data.getData(); // get image data to upload try { sendImageMessage(imageuri); } catch (IOException e) { e.printStackTrace(); } } if (requestCode == IMAGE_PICKCAMERA_REQUEST) { try { sendImageMessage(imageuri); } catch (IOException e) { e.printStackTrace(); } } } super .onActivityResult(requestCode, resultCode, data); } private void sendImageMessage(Uri imageuri) throws IOException { notify = true ; final ProgressDialog dialog = new ProgressDialog( this ); dialog.setMessage( "Sending Image" ); dialog.show(); // If we are sending image as a message // then we need to find the url of // image after uploading the // image in firebase storage final String timestamp = "" + System.currentTimeMillis(); String filepathandname = "ChatImages/" + "post" + timestamp; // filename Bitmap bitmap = MediaStore.Images.Media.getBitmap( this .getContentResolver(), imageuri); ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100 , arrayOutputStream); // compressing the image using bitmap final byte [] data = arrayOutputStream.toByteArray(); StorageReference ref = FirebaseStorage.getInstance().getReference().child(filepathandname); ref.putBytes(data).addOnSuccessListener( new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { dialog.dismiss(); Task<Uri> uriTask = taskSnapshot.getStorage().getDownloadUrl(); while (!uriTask.isSuccessful()) ; String downloadUri = uriTask.getResult().toString(); // getting url if task is successful if (uriTask.isSuccessful()) { DatabaseReference re = FirebaseDatabase.getInstance().getReference(); HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put( "sender" , myuid); hashMap.put( "receiver" , uid); hashMap.put( "message" , downloadUri); hashMap.put( "timestamp" , timestamp); hashMap.put( "dilihat" , false ); hashMap.put( "type" , "images" ); re.child( "Chats" ).push().setValue(hashMap); // push in firebase using unique id final DatabaseReference ref1 = FirebaseDatabase.getInstance().getReference( "ChatList" ).child(uid).child(myuid); ref1.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { if (!dataSnapshot.exists()) { ref1.child( "id" ).setValue(myuid); } } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); final DatabaseReference ref2 = FirebaseDatabase.getInstance().getReference( "ChatList" ).child(myuid).child(uid); ref2.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { if (!dataSnapshot.exists()) { ref2.child( "id" ).setValue(uid); } } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); } } }).addOnFailureListener( new OnFailureListener() { @Override public void onFailure( @NonNull Exception e) { } }); } private Boolean checkCameraPermission() { boolean result = ContextCompat.checkSelfPermission( this , Manifest.permission.CAMERA) == (PackageManager.PERMISSION_GRANTED); boolean result1 = ContextCompat.checkSelfPermission( this , Manifest.permission.WRITE_EXTERNAL_STORAGE) == (PackageManager.PERMISSION_GRANTED); return result && result1; } private void requestCameraPermission() { requestPermissions(cameraPermission, CAMERA_REQUEST); } private void pickFromCamera() { ContentValues contentValues = new ContentValues(); contentValues.put(MediaStore.Images.Media.TITLE, "Temp_pic" ); contentValues.put(MediaStore.Images.Media.DESCRIPTION, "Temp Description" ); imageuri = this .getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); Intent camerIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); camerIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageuri); startActivityForResult(camerIntent, IMAGE_PICKCAMERA_REQUEST); } private void pickFromGallery() { Intent galleryIntent = new Intent(Intent.ACTION_PICK); galleryIntent.setType( "image/*" ); startActivityForResult(galleryIntent, IMAGEPICK_GALLERY_REQUEST); } private Boolean checkStoragePermission() { boolean result = ContextCompat.checkSelfPermission(ChatActivity. this , Manifest.permission.WRITE_EXTERNAL_STORAGE) == (PackageManager.PERMISSION_GRANTED); return result; } private void requestStoragePermission() { requestPermissions(storagePermission, STORAGE_REQUEST); } private void sendmessage( final String message) { // creating a reference to store data in firebase // We will be storing data using current time in "Chatlist" // and we are pushing data using unique id in "Chats" DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference(); String timestamp = String.valueOf(System.currentTimeMillis()); HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put( "sender" , myuid); hashMap.put( "receiver" , uid); hashMap.put( "message" , message); hashMap.put( "timestamp" , timestamp); hashMap.put( "dilihat" , false ); hashMap.put( "type" , "text" ); databaseReference.child( "Chats" ).push().setValue(hashMap); final DatabaseReference ref1 = FirebaseDatabase.getInstance().getReference( "ChatList" ).child(uid).child(myuid); ref1.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { if (!dataSnapshot.exists()) { ref1.child( "id" ).setValue(myuid); } } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); final DatabaseReference ref2 = FirebaseDatabase.getInstance().getReference( "ChatList" ).child(myuid).child(uid); ref2.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { if (!dataSnapshot.exists()) { ref2.child( "id" ).setValue(uid); } } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); } @Override public boolean onOptionsItemSelected( @NonNull MenuItem item) { if (item.getItemId() == R.id.logout) { firebaseAuth.signOut(); checkUserStatus(); } return super .onOptionsItemSelected(item); } private void checkUserStatus() { FirebaseUser user = firebaseAuth.getCurrentUser(); if (user != null ) { myuid = user.getUid(); } } } |
Output:
Showing All Chat in ChatList Fragment
Step 1: Working with the ModelChatlist.xml file
Getting the id of users to whom we have sent messages.
Java
package com.example.socialmediaapp; class ModelChatList { public String getId() { return id; } public void setId(String id) { this .id = id; } public ModelChatList() { } public ModelChatList(String id) { this .id = id; } String id; } |
Step 2: Working with the AdapterChatList.java file
Showing the users and the last message sent in the chat.
Java
package com.example.socialmediaapp; import android.content.Context; import android.content.Intent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.google.firebase.auth.FirebaseAuth; import java.util.HashMap; import java.util.List; public class AdapterChatList extends RecyclerView.Adapter<AdapterChatList.Myholder> { Context context; FirebaseAuth firebaseAuth; String uid; public AdapterChatList(Context context, List<ModelUsers> users) { this .context = context; this .usersList = users; lastMessageMap = new HashMap<>(); firebaseAuth = FirebaseAuth.getInstance(); uid = firebaseAuth.getUid(); } List<ModelUsers> usersList; private HashMap<String, String> lastMessageMap; @NonNull @Override public Myholder onCreateViewHolder( @NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.row_chatlist, parent, false ); return new Myholder(view); } @Override public void onBindViewHolder( @NonNull Myholder holder, final int position) { final String hisuid = usersList.get(position).getUid(); String userimage = usersList.get(position).getImage(); String username = usersList.get(position).getName(); String lastmess = lastMessageMap.get(hisuid); holder.name.setText(username); holder.block.setImageResource(R.drawable.ic_unblock); // if no last message then Hide the layout if (lastmess == null || lastmess.equals( "default" )) { holder.lastmessage.setVisibility(View.GONE); } else { holder.lastmessage.setVisibility(View.VISIBLE); holder.lastmessage.setText(lastmess); } try { // loading profile pic of user Glide.with(context).load(userimage).into(holder.profile); } catch (Exception e) { } // redirecting to chat activity on item click holder.itemView.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(context, ChatActivity. class ); // putting uid of user in extras intent.putExtra( "uid" , hisuid); context.startActivity(intent); } }); } // setting last message sent by users. public void setlastMessageMap(String userId, String lastmessage) { lastMessageMap.put(userId, lastmessage); } @Override public int getItemCount() { return usersList.size(); } class Myholder extends RecyclerView.ViewHolder { ImageView profile, status, block, seen; TextView name, lastmessage; public Myholder( @NonNull View itemView) { super (itemView); profile = itemView.findViewById(R.id.profileimage); status = itemView.findViewById(R.id.onlinestatus); name = itemView.findViewById(R.id.nameonline); lastmessage = itemView.findViewById(R.id.lastmessge); block = itemView.findViewById(R.id.blocking); seen = itemView.findViewById(R.id.seen); } } } |
Step 3: Working with the fragment_chatlist.xml file
Showing all the users using the recycler view.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < FrameLayout android:layout_width = "match_parent" android:layout_height = "match_parent" tools:context = ".ChatListFragment" > < androidx.recyclerview.widget.RecyclerView android:id = "@+id/chatlistrecycle" android:layout_width = "match_parent" android:layout_height = "match_parent" app:layoutManager = "androidx.recyclerview.widget.LinearLayoutManager" tools:listitem = "@layout/row_chatlist" /> </ FrameLayout > |
Step 4: Working with the ChatlistFragment.java file
Here we are showing all the users to whom we have sent messages. This is how we will get the last message of the current user. If the message type is images then simply set the last message as “Sent a photo”.
if(chat.getReceiver().equals(firebaseUser.getUid())&& chat.getSender().equals(uid)|| chat.getReceiver().equals(uid)&& chat.getSender().equals(firebaseUser.getUid())){ if(chat.getType().equals("images")){ lastmess="Sent a Photo"; } else { lastmess = chat.getMessage(); } }
Below is the code for the ChatlistFragment.java file.
Java
package com.example.socialmediaapp; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; import java.util.ArrayList; import java.util.List; /** * A simple {@link Fragment} subclass. */ public class ChatListFragment extends Fragment { FirebaseAuth firebaseAuth; RecyclerView recyclerView; List<ModelChatList> chatListList; List<ModelUsers> usersList; DatabaseReference reference; FirebaseUser firebaseUser; AdapterChatList adapterChatList; List<ModelChat> chatList; public ChatListFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_chat_list, container, false ); firebaseAuth = FirebaseAuth.getInstance(); // getting current user firebaseUser = FirebaseAuth.getInstance().getCurrentUser(); recyclerView = view.findViewById(R.id.chatlistrecycle); chatListList = new ArrayList<>(); chatList = new ArrayList<>(); reference = FirebaseDatabase.getInstance().getReference( "ChatList" ).child(firebaseUser.getUid()); reference.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { chatListList.clear(); for (DataSnapshot ds : dataSnapshot.getChildren()) { ModelChatList modelChatList = ds.getValue(ModelChatList. class ); if (!modelChatList.getId().equals(firebaseUser.getUid())) { chatListList.add(modelChatList); } } loadChats(); } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); return view; } // loading the user chat layout using chat node private void loadChats() { usersList = new ArrayList<>(); reference = FirebaseDatabase.getInstance().getReference( "Users" ); reference.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { usersList.clear(); for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) { ModelUsers user = dataSnapshot1.getValue(ModelUsers. class ); for (ModelChatList chatList : chatListList) { if (user.getUid() != null && user.getUid().equals(chatList.getId())) { usersList.add(user); break ; } } adapterChatList = new AdapterChatList(getActivity(), usersList); recyclerView.setAdapter(adapterChatList); // getting last message of the user for ( int i = 0 ; i < usersList.size(); i++) { lastMessage(usersList.get(i).getUid()); } } } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); } private void lastMessage( final String uid) { DatabaseReference ref = FirebaseDatabase.getInstance().getReference( "Chats" ); ref.addValueEventListener( new ValueEventListener() { @Override public void onDataChange( @NonNull DataSnapshot dataSnapshot) { String lastmess = "default" ; for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) { ModelChat chat = dataSnapshot1.getValue(ModelChat. class ); if (chat == null ) { continue ; } String sender = chat.getSender(); String receiver = chat.getReceiver(); if (sender == null || receiver == null ) { continue ; } // checking for the type of message if // message type is image then set // last message as sent a photo if (chat.getReceiver().equals(firebaseUser.getUid()) && chat.getSender().equals(uid) || chat.getReceiver().equals(uid) && chat.getSender().equals(firebaseUser.getUid())) { if (chat.getType().equals( "images" )) { lastmess = "Sent a Photo" ; } else { lastmess = chat.getMessage(); } } } adapterChatList.setlastMessageMap(uid, lastmess); adapterChatList.notifyDataSetChanged(); } @Override public void onCancelled( @NonNull DatabaseError databaseError) { } }); } @Override public void onCreate( @Nullable Bundle savedInstanceState) { setHasOptionsMenu( true ); super .onCreate(savedInstanceState); } } |
Output:
For all the drawable file used in this article please refer to this link: https://drive.google.com/drive/folders/1M_knOH_ugCuwSP5nkYzeD4dRp-Honzbe?usp=sharing
Below is the file structure after performing these operations: