2025-12-19 15:11:49 +08:00
|
|
|
|
package com.example.livestreaming;
|
|
|
|
|
|
|
2025-12-22 16:31:46 +08:00
|
|
|
|
import android.graphics.Outline;
|
|
|
|
|
|
import android.net.Uri;
|
|
|
|
|
|
import android.text.TextUtils;
|
2025-12-19 15:11:49 +08:00
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
|
|
import android.view.View;
|
|
|
|
|
|
import android.view.ViewGroup;
|
2025-12-22 16:31:46 +08:00
|
|
|
|
import android.view.ViewOutlineProvider;
|
|
|
|
|
|
import android.widget.ImageView;
|
2025-12-19 15:11:49 +08:00
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
|
import androidx.recyclerview.widget.DiffUtil;
|
|
|
|
|
|
import androidx.recyclerview.widget.ListAdapter;
|
|
|
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
|
|
|
2025-12-22 16:31:46 +08:00
|
|
|
|
import com.bumptech.glide.Glide;
|
|
|
|
|
|
|
2025-12-19 15:11:49 +08:00
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
|
import java.util.Locale;
|
|
|
|
|
|
|
|
|
|
|
|
public class ConversationMessagesAdapter extends ListAdapter<ChatMessage, RecyclerView.ViewHolder> {
|
|
|
|
|
|
|
|
|
|
|
|
private static final int TYPE_INCOMING = 1;
|
|
|
|
|
|
private static final int TYPE_OUTGOING = 2;
|
|
|
|
|
|
|
|
|
|
|
|
private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
|
|
|
|
|
|
|
|
|
|
|
public ConversationMessagesAdapter() {
|
|
|
|
|
|
super(DIFF);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public int getItemViewType(int position) {
|
|
|
|
|
|
ChatMessage msg = getItem(position);
|
|
|
|
|
|
if (msg == null) return TYPE_INCOMING;
|
|
|
|
|
|
String u = msg.getUsername();
|
|
|
|
|
|
return "我".equals(u) ? TYPE_OUTGOING : TYPE_INCOMING;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
|
|
|
|
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
|
|
|
|
|
if (viewType == TYPE_OUTGOING) {
|
|
|
|
|
|
View v = inflater.inflate(R.layout.item_conversation_message_outgoing, parent, false);
|
|
|
|
|
|
return new OutgoingVH(v);
|
|
|
|
|
|
}
|
|
|
|
|
|
View v = inflater.inflate(R.layout.item_conversation_message_incoming, parent, false);
|
|
|
|
|
|
return new IncomingVH(v);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
|
|
|
|
|
ChatMessage msg = getItem(position);
|
|
|
|
|
|
if (holder instanceof IncomingVH) {
|
|
|
|
|
|
((IncomingVH) holder).bind(msg);
|
|
|
|
|
|
} else if (holder instanceof OutgoingVH) {
|
|
|
|
|
|
((OutgoingVH) holder).bind(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static class IncomingVH extends RecyclerView.ViewHolder {
|
2025-12-22 16:31:46 +08:00
|
|
|
|
private final ImageView avatarView;
|
2025-12-19 15:11:49 +08:00
|
|
|
|
private final TextView nameText;
|
|
|
|
|
|
private final TextView msgText;
|
|
|
|
|
|
private final TextView timeText;
|
|
|
|
|
|
|
|
|
|
|
|
IncomingVH(@NonNull View itemView) {
|
|
|
|
|
|
super(itemView);
|
2025-12-22 16:31:46 +08:00
|
|
|
|
avatarView = itemView.findViewById(R.id.avatarView);
|
2025-12-19 15:11:49 +08:00
|
|
|
|
nameText = itemView.findViewById(R.id.nameText);
|
|
|
|
|
|
msgText = itemView.findViewById(R.id.messageText);
|
|
|
|
|
|
timeText = itemView.findViewById(R.id.timeText);
|
2025-12-22 16:31:46 +08:00
|
|
|
|
setupAvatarOutline();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void setupAvatarOutline() {
|
|
|
|
|
|
if (avatarView == null) return;
|
|
|
|
|
|
// 设置圆形裁剪,确保在模拟器上也能正常工作
|
|
|
|
|
|
// 使用post确保在View布局完成后再设置outline
|
|
|
|
|
|
avatarView.post(() -> {
|
|
|
|
|
|
if (avatarView.getWidth() > 0 && avatarView.getHeight() > 0) {
|
|
|
|
|
|
avatarView.setOutlineProvider(new ViewOutlineProvider() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void getOutline(View view, Outline outline) {
|
|
|
|
|
|
outline.setOval(0, 0, view.getWidth(), view.getHeight());
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
avatarView.setClipToOutline(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-12-19 15:11:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void bind(ChatMessage message) {
|
|
|
|
|
|
if (message == null) return;
|
|
|
|
|
|
nameText.setText(message.getUsername() != null ? message.getUsername() : "");
|
|
|
|
|
|
msgText.setText(message.getMessage() != null ? message.getMessage() : "");
|
|
|
|
|
|
timeText.setText(TIME_FORMAT.format(new Date(message.getTimestamp())));
|
2025-12-22 16:31:46 +08:00
|
|
|
|
|
|
|
|
|
|
// 确保头像圆形裁剪设置正确
|
|
|
|
|
|
setupAvatarOutline();
|
|
|
|
|
|
// 加载对方头像(可以根据用户名或其他信息加载)
|
|
|
|
|
|
loadAvatar(message.getUsername());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void loadAvatar(String username) {
|
|
|
|
|
|
if (avatarView == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 这里可以根据用户名加载对应的头像
|
|
|
|
|
|
// 暂时使用默认头像,后续可以根据实际需求从服务器或本地加载
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 可以根据username从SharedPreferences或其他地方加载头像
|
|
|
|
|
|
// 这里先使用默认头像,使用Glide确保圆形裁剪
|
|
|
|
|
|
Glide.with(avatarView)
|
|
|
|
|
|
.load(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.into(avatarView);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
Glide.with(avatarView)
|
|
|
|
|
|
.load(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.into(avatarView);
|
|
|
|
|
|
}
|
2025-12-19 15:11:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static class OutgoingVH extends RecyclerView.ViewHolder {
|
2025-12-22 16:31:46 +08:00
|
|
|
|
private final ImageView avatarView;
|
2025-12-19 15:11:49 +08:00
|
|
|
|
private final TextView msgText;
|
|
|
|
|
|
private final TextView timeText;
|
|
|
|
|
|
|
|
|
|
|
|
OutgoingVH(@NonNull View itemView) {
|
|
|
|
|
|
super(itemView);
|
2025-12-22 16:31:46 +08:00
|
|
|
|
avatarView = itemView.findViewById(R.id.avatarView);
|
2025-12-19 15:11:49 +08:00
|
|
|
|
msgText = itemView.findViewById(R.id.messageText);
|
|
|
|
|
|
timeText = itemView.findViewById(R.id.timeText);
|
2025-12-22 16:31:46 +08:00
|
|
|
|
setupAvatarOutline();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void setupAvatarOutline() {
|
|
|
|
|
|
if (avatarView == null) return;
|
|
|
|
|
|
// 设置圆形裁剪,确保在模拟器上也能正常工作
|
|
|
|
|
|
// 使用post确保在View布局完成后再设置outline
|
|
|
|
|
|
avatarView.post(() -> {
|
|
|
|
|
|
if (avatarView.getWidth() > 0 && avatarView.getHeight() > 0) {
|
|
|
|
|
|
avatarView.setOutlineProvider(new ViewOutlineProvider() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void getOutline(View view, Outline outline) {
|
|
|
|
|
|
outline.setOval(0, 0, view.getWidth(), view.getHeight());
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
avatarView.setClipToOutline(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-12-19 15:11:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void bind(ChatMessage message) {
|
|
|
|
|
|
if (message == null) return;
|
|
|
|
|
|
msgText.setText(message.getMessage() != null ? message.getMessage() : "");
|
|
|
|
|
|
timeText.setText(TIME_FORMAT.format(new Date(message.getTimestamp())));
|
2025-12-22 16:31:46 +08:00
|
|
|
|
|
|
|
|
|
|
// 确保头像圆形裁剪设置正确
|
|
|
|
|
|
setupAvatarOutline();
|
|
|
|
|
|
// 加载用户头像
|
|
|
|
|
|
loadAvatar();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void loadAvatar() {
|
|
|
|
|
|
if (avatarView == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
String avatarUri = avatarView.getContext()
|
|
|
|
|
|
.getSharedPreferences("profile_prefs", android.content.Context.MODE_PRIVATE)
|
|
|
|
|
|
.getString("profile_avatar_uri", null);
|
|
|
|
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(avatarUri)) {
|
|
|
|
|
|
Glide.with(avatarView)
|
|
|
|
|
|
.load(Uri.parse(avatarUri))
|
|
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.error(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.into(avatarView);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int avatarRes = avatarView.getContext()
|
|
|
|
|
|
.getSharedPreferences("profile_prefs", android.content.Context.MODE_PRIVATE)
|
|
|
|
|
|
.getInt("profile_avatar_res", 0);
|
|
|
|
|
|
|
|
|
|
|
|
if (avatarRes != 0) {
|
|
|
|
|
|
Glide.with(avatarView)
|
|
|
|
|
|
.load(avatarRes)
|
|
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.error(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.into(avatarView);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Glide.with(avatarView)
|
|
|
|
|
|
.load(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.into(avatarView);
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
Glide.with(avatarView)
|
|
|
|
|
|
.load(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.into(avatarView);
|
|
|
|
|
|
}
|
2025-12-19 15:11:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static final DiffUtil.ItemCallback<ChatMessage> DIFF = new DiffUtil.ItemCallback<ChatMessage>() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public boolean areItemsTheSame(@NonNull ChatMessage oldItem, @NonNull ChatMessage newItem) {
|
|
|
|
|
|
return oldItem.getTimestamp() == newItem.getTimestamp();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public boolean areContentsTheSame(@NonNull ChatMessage oldItem, @NonNull ChatMessage newItem) {
|
|
|
|
|
|
return oldItem.getTimestamp() == newItem.getTimestamp();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|