made it so we can put attachments to chat

- Sending not implemented until backend is complete
This commit is contained in:
Alex
2026-04-02 18:23:49 -06:00
parent 6afda8e7b8
commit 0216435221
6 changed files with 257 additions and 13 deletions

View File

@@ -22,6 +22,15 @@ public class MessageDTO {
@SerializedName("isRead")
private Boolean isRead;
@SerializedName("attachmentUrl")
private String attachmentUrl;
@SerializedName("attachmentName")
private String attachmentName;
@SerializedName("attachmentType")
private String attachmentType;
public MessageDTO() {}
public Long getId() { return id; }
@@ -41,4 +50,13 @@ public class MessageDTO {
public Boolean getIsRead() { return isRead; }
public void setIsRead(Boolean isRead) { this.isRead = isRead; }
public String getAttachmentUrl() { return attachmentUrl; }
public void setAttachmentUrl(String attachmentUrl) { this.attachmentUrl = attachmentUrl; }
public String getAttachmentName() { return attachmentName; }
public void setAttachmentName(String attachmentName) { this.attachmentName = attachmentName; }
public String getAttachmentType() { return attachmentType; }
public void setAttachmentType(String attachmentType) { this.attachmentType = attachmentType; }
}

View File

@@ -1,15 +1,23 @@
package com.example.petstoremobile.fragments;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.OpenableColumns;
import android.util.Log;
import android.view.*;
import android.widget.*;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.example.petstoremobile.R;
import com.example.petstoremobile.adapters.ChatAdapter;
import com.example.petstoremobile.adapters.MessageAdapter;
@@ -41,8 +49,15 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
private RecyclerView rvChatList, rvMessages;
private EditText etMessage;
private Button btnSend;
private ImageButton btnAttach;
private TextView tvChatTitle;
// Preview views
private View layoutAttachmentPreview;
private ImageView ivPreview;
private TextView tvPreviewName;
private ImageButton btnRemoveAttachment;
// Adapters
private ChatAdapter chatAdapter;
private MessageAdapter messageAdapter;
@@ -51,6 +66,7 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
private final List<Chat> chatList = new ArrayList<>();
private final List<Message> messageList = new ArrayList<>();
private final Map<Long, String> customerNames = new HashMap<>();
private Uri pendingAttachmentUri;
// APIs
private ChatApi chatApi;
@@ -61,6 +77,24 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
private Long currentUserId;
private Long activeConversationId;
private StompChatManager stompChatManager;
private ActivityResultLauncher<Intent> attachmentLauncher;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
attachmentLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
Uri uri = result.getData().getData();
if (uri != null) {
showAttachmentPreview(uri);
}
}
}
);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@@ -77,11 +111,28 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
rvMessages = view.findViewById(R.id.rvMessages);
etMessage = view.findViewById(R.id.etMessage);
btnSend = view.findViewById(R.id.btnSend);
btnAttach = view.findViewById(R.id.btnAttach);
tvChatTitle = view.findViewById(R.id.tvChatTitle);
layoutAttachmentPreview = view.findViewById(R.id.layoutAttachmentPreview);
ivPreview = view.findViewById(R.id.ivPreview);
tvPreviewName = view.findViewById(R.id.tvPreviewName);
btnRemoveAttachment = view.findViewById(R.id.btnRemoveAttachment);
ImageButton hamburger = view.findViewById(R.id.btnHamburger);
hamburger.setOnClickListener(v -> drawerLayout.openDrawer(GravityCompat.START));
btnSend.setOnClickListener(v -> sendMessage());
//When the send button is clicked check if there is an attachment and send using the correct helper function
btnSend.setOnClickListener(v -> {
if (pendingAttachmentUri != null) {
sendWithAttachment(pendingAttachmentUri);
} else {
sendMessage();
}
});
//When the attachment button is clicked open the file picker
btnAttach.setOnClickListener(v -> selectAttachment());
btnRemoveAttachment.setOnClickListener(v -> removeAttachment());
setupRecyclerViews();
loadInitialData();
@@ -89,6 +140,7 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
return view;
}
// Helper function to setup recycler views for chat and messages
private void setupRecyclerViews() {
// Set up Drawer menu to select conversation
chatAdapter = new ChatAdapter(chatList, this);
@@ -273,6 +325,68 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
});
}
//Helper function to open file picker when the attachment button is clicked
private void selectAttachment() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
attachmentLauncher.launch(intent);
}
//Helper function to show the attachment preview
private void showAttachmentPreview(Uri uri) {
pendingAttachmentUri = uri;
layoutAttachmentPreview.setVisibility(View.VISIBLE);
String mimeType = requireContext().getContentResolver().getType(uri);
String fileName = getFileName(uri);
tvPreviewName.setText(fileName);
// If the file is an image, display a thumbnail of the image as well
if (mimeType != null && mimeType.startsWith("image/")) {
ivPreview.setVisibility(View.VISIBLE);
Glide.with(this).load(uri).into(ivPreview);
} else {
ivPreview.setVisibility(View.GONE);
}
}
//Helper function to remove the attachment
private void removeAttachment() {
pendingAttachmentUri = null;
layoutAttachmentPreview.setVisibility(View.GONE);
}
//Helper function to get the file name from the uri to display in attachment preview
private String getFileName(Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
try (Cursor cursor = requireContext().getContentResolver().query(uri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (index != -1) {
result = cursor.getString(index);
}
}
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
//Helper function to send the message with attachment
private void sendWithAttachment(Uri uri) {
if (activeConversationId == null) return;
//TODO: send the message with attachment when backend is done
Log.d(TAG, "Send with attachment happening");
}
// When a message is received updates the chat preview
@Override
public void onMessageReceived(MessageDTO dto) {
@@ -370,6 +484,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
m.setContent(dto.getContent());
m.setTimestamp(dto.getTimestamp());
m.setIsRead(dto.getIsRead());
m.setAttachmentUrl(dto.getAttachmentUrl());
m.setAttachmentName(dto.getAttachmentName());
m.setAttachmentType(dto.getAttachmentType());
return m;
}
@@ -407,9 +524,11 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
private void setConversationActive(boolean active) {
btnSend.setEnabled(active);
etMessage.setEnabled(active);
btnAttach.setEnabled(active);
if (!active) {
activeConversationId = null;
ChatNotificationService.activeConversationIdInUi = null;
removeAttachment();
if (tvChatTitle != null) tvChatTitle.setText("Customer Chat");
if (stompChatManager != null) {
stompChatManager.clearConversationSubscription();

View File

@@ -7,6 +7,9 @@ public class Message {
private String content;
private String timestamp;
private Boolean isRead;
private String attachmentUrl;
private String attachmentName;
private String attachmentType;
public Message() {}
@@ -33,4 +36,13 @@ public class Message {
public Boolean getIsRead() { return isRead; }
public void setIsRead(Boolean isRead) { this.isRead = isRead; }
public String getAttachmentUrl() { return attachmentUrl; }
public void setAttachmentUrl(String attachmentUrl) { this.attachmentUrl = attachmentUrl; }
public String getAttachmentName() { return attachmentName; }
public void setAttachmentName(String attachmentName) { this.attachmentName = attachmentName; }
public String getAttachmentType() { return attachmentType; }
public void setAttachmentType(String attachmentType) { this.attachmentType = attachmentType; }
}

View File

@@ -49,12 +49,59 @@
android:clipToPadding="false" />
<LinearLayout
android:id="@+id/layoutAttachmentPreview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
android:background="#E0E0E0"
android:gravity="center_vertical"
android:visibility="gone">
<ImageView
android:id="@+id/ivPreview"
android:layout_width="48dp"
android:layout_height="48dp"
android:scaleType="centerCrop"
android:layout_marginEnd="8dp"
android:visibility="gone"/>
<TextView
android:id="@+id/tvPreviewName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="middle"
android:singleLine="true"
android:textColor="@color/text_dark"/>
<ImageButton
android:id="@+id/btnRemoveAttachment"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@android:drawable/ic_menu_close_clear_cancel"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Remove attachment"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
android:gravity="center_vertical"
android:background="@color/white">
<ImageButton
android:id="@+id/btnAttach"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@android:drawable/ic_menu_add"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Attach file"
android:layout_marginEnd="4dp"/>
<EditText
android:id="@+id/etMessage"
android:layout_width="0dp"

View File

@@ -6,14 +6,38 @@
android:padding="8dp"
android:gravity="start">
<TextView
android:id="@+id/tvMessageContent"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/bg_message_received"
android:padding="12dp"
android:text="Received message"
android:textColor="@color/text_dark"
android:maxWidth="300dp" />
android:padding="8dp"
android:maxWidth="300dp">
<ImageView
android:id="@+id/ivAttachment"
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:visibility="gone"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/tvAttachmentName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_dark"
android:textStyle="italic"
android:textSize="12sp"
android:visibility="gone"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/tvMessageContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Received message"
android:textColor="@color/text_dark" />
</LinearLayout>
</LinearLayout>

View File

@@ -6,14 +6,38 @@
android:padding="8dp"
android:gravity="end">
<TextView
android:id="@+id/tvMessageContent"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/bg_message_sent"
android:padding="12dp"
android:text="Sent message"
android:textColor="@color/white"
android:maxWidth="300dp" />
android:padding="8dp"
android:maxWidth="300dp">
<ImageView
android:id="@+id/ivAttachment"
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:visibility="gone"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/tvAttachmentName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textStyle="italic"
android:textSize="12sp"
android:visibility="gone"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/tvMessageContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sent message"
android:textColor="@color/white" />
</LinearLayout>
</LinearLayout>