Esta es la Parte 14 del tutorial «Crear una aplicación de redes sociales en Android Studio» , y vamos a cubrir las siguientes funcionalidades en este artículo:
- Vamos a crear un diseño para el chat y enviar mensajes en el chat.
- Un usuario puede enviar un mensaje o una imagen.
- Un usuario puede enviar una imagen usando una cámara o una galería.
- En primer lugar, se solicitará una solicitud de permiso para enviar una imagen mediante una galería o después de hacer clic en la imagen con la cámara.
- Si se otorga permiso, el usuario puede enviar la imagen, o volverá a solicitar permiso.
Implementación paso a paso
Paso 1: Cree dos nuevos archivos de recursos de diseño y llámelos row_chat_left y row_chat_right
Trabajando con el archivo row_chat_left.xml . El mensaje recibido estará en el lado izquierdo. Del mismo modo, Trabajar con row_chat_right . archivo xml . El mensaje que se envía al usuario estará en el lado derecho. A continuación se muestra el código para el archivo row_chat_left.xml y row_chat_right . archivo xml .
XML
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" 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 xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" 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>
Paso 2: trabajar con el archivo activity_chat.xml
Aquí, en RecyclerView , mostraremos todos los mensajes. En TextView , el usuario escribirá el mensaje y usando el botón Enviar, el usuario enviará el mensaje. A continuación se muestra el código para el archivo activity_chat.xml .
XML
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="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>
Paso 3: trabajar con el archivo row_chatlist.xml
Cree otro archivo de recursos de diseño y asígnele el nombre row_chatlist . A continuación se muestra el código para el archivo row_chatlist.xml .
XML
<?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="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>
Paso 4: trabajar con el archivo ModelChat.java
Creó esta clase para inicializar la clave para que podamos recuperar el valor de la clave más tarde.
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; }
Paso 5: trabajar con el archivo AdpaterChat.java
Cree una nueva clase Java y nombre la clase como AdpaterChat. A continuación se muestra el código para el archivo AdpaterChat.java .
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); } } }
Paso 6: trabajar con el archivo ChatActivity.java
Estamos leyendo el mensaje de usuario del Node «Chats» en Firebase. Cada vez que los datos cambien, estos datos cambiarán en consecuencia.
chatList=new ArrayList<>(); DatabaseReference dbref= FirebaseDatabase.getInstance().getReference().child("Chats");
Cargando el valor de datos de configuración de datos usando el chat del adaptador
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);
Envío de mensajes en valor de Node de referencia de chat. Así es como estamos guardando datos en la base de datos Firebase Realtime
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);
A continuación se muestra el código para el archivo ChatActivity.java .
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(); } } }
Producción:
Mostrar todo el chat en el fragmento de ChatList
Paso 1: trabajar con el archivo ModelChatlist.xml
Obtener el id de los usuarios a los que hemos enviado mensajes.
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; }
Paso 2: trabajar con el archivo AdapterChatList.java
Mostrando los usuarios y el último mensaje enviado en el 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); } } }
Paso 3: trabajar con el archivo fragment_chatlist.xml
Mostrando todos los usuarios que utilizan la vista del reciclador.
XML
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="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>
Paso 4: trabajar con el archivo ChatlistFragment.java
Aquí estamos mostrando todos los usuarios a los que hemos enviado mensajes. Así obtendremos el último mensaje del usuario actual. Si el tipo de mensaje son imágenes, simplemente configure el último mensaje como «Enviado una foto».
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(); } }
A continuación se muestra el código para el archivo ChatlistFragment.java .
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); } }
Producción:
Para ver todos los archivos dibujables utilizados en este artículo, consulte este enlace: https://drive.google.com/drive/folders/1M_knOH_ugCuwSP5nkYzeD4dRp-Honzbe?usp=sharing
A continuación se muestra la estructura de archivos después de realizar estas operaciones: