diff --git a/app/src/main/java/com/example/tampopo_client/Tampopo.java b/app/src/main/java/com/example/tampopo_client/Tampopo.java index c4d1267..c5edc9b 100644 --- a/app/src/main/java/com/example/tampopo_client/Tampopo.java +++ b/app/src/main/java/com/example/tampopo_client/Tampopo.java @@ -12,6 +12,7 @@ private String userId; private String password; private String chatroomId; + private String chatFriendId; private String mailaddress; private String nickname; private String icon; @@ -54,6 +55,13 @@ public void setChatroomId(String ChatroomId) { this.chatroomId = ChatroomId; } + public String getChatFriendId() { + return chatFriendId; + } + + public void setChatFriendId(String ChatFriendId) { + this.chatFriendId = ChatFriendId; + } public String getNickname() { return nickname; } diff --git a/app/src/main/java/com/example/tampopo_client/models/Chatroom.java b/app/src/main/java/com/example/tampopo_client/models/Chatroom.java index 74622ba..4fe8b21 100644 --- a/app/src/main/java/com/example/tampopo_client/models/Chatroom.java +++ b/app/src/main/java/com/example/tampopo_client/models/Chatroom.java @@ -1,49 +1,134 @@ package com.example.tampopo_client.models; +import java.util.ArrayList; +import java.util.List; + public class Chatroom { - private String chatroomId; // チャットルームのID - private String partnerUserId; // 相手ユーザーID - private String user1Id; // 1人目のユーザーID - private String user2Id; // 2人目のユーザーID - public Chatroom() {} - public Chatroom(String chatroomId, String user1Id, String user2Id) { - this.chatroomId = chatroomId; + private String chatRoomId; + private String user0Id; + private String user1Id; + private String newContent; + private String chatRoomNumber; // サーバーにも存在するので保持 + private List messages = new ArrayList<>(); + private List users = new ArrayList<>(); + + // --- コンストラクタ --- + public Chatroom() { + } + + public Chatroom(String chatRoomId, String user0Id, String user1Id) { + this.chatRoomId = chatRoomId; + this.user0Id = user0Id; this.user1Id = user1Id; - this.user2Id = user2Id; + this.users.add(user0Id); + this.users.add(user1Id); } - - public Chatroom(String chatroomId,String partnerUserId) { - this.chatroomId = chatroomId; - this.partnerUserId = partnerUserId; + // --- Getter / Setter --- + public String getChatRoomId() { + return chatRoomId; } - public String getChatroomId() { - return chatroomId; + public void setChatRoomId(String chatRoomId) { + this.chatRoomId = chatRoomId; } - public void setChatroomId(String chatroomId) { - this.chatroomId = chatroomId; + public String getUser0Id() { + return user0Id; + } + + public void setUser0Id(String user0Id) { + this.user0Id = user0Id; } public String getUser1Id() { return user1Id; } - - - public String getUser2Id() { - return user2Id; + public void setUser1Id(String user1Id) { + this.user1Id = user1Id; } - - public String getPartnerUserId() { - return partnerUserId; + public String getNewContent() { + return newContent; } - public void setPartnerUserId(String partnerUserId) { - this.partnerUserId = partnerUserId; + public void setNewContent(String newContent) { + this.newContent = newContent; } -} + public String getChatRoomNumber() { + return chatRoomNumber; + } + + public void setChatRoomNumber(String chatRoomNumber) { + this.chatRoomNumber = chatRoomNumber; + } + + public List getMessages() { + return messages; + } + + public void setMessages(List messages) { + this.messages = messages; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + // --- メッセージ追加 --- + public void addMessage(String senderId, String content) { + messages.add(new Message(senderId, content)); + } + + // --- ユーザー操作 --- + public void addUser(String userId) { + if (!users.contains(userId)) { + users.add(userId); + } + } + + public boolean removeUser(String userId) { + return users.remove(userId); + } + + public boolean isEmpty() { + return users.isEmpty(); + } + + // --- 内部クラス Message --- + public static class Message { + private String senderId; + private String content; + + public Message() { + } + + public Message(String senderId, String content) { + this.senderId = senderId; + this.content = content; + } + + public String getSenderId() { + return senderId; + } + + public void setSenderId(String senderId) { + this.senderId = senderId; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tampopo_client/resources/ChatroomResource.java b/app/src/main/java/com/example/tampopo_client/resources/ChatroomResource.java index 4384636..3402974 100644 --- a/app/src/main/java/com/example/tampopo_client/resources/ChatroomResource.java +++ b/app/src/main/java/com/example/tampopo_client/resources/ChatroomResource.java @@ -17,42 +17,42 @@ public interface ChatroomResource { // チャットルームに入る - @POST("enterChatroom") + @POST("chat-rooms") Call enterChatroom( - @Query("myId") String myId, - @Query("partnerId") String partnerId, - @Header("Authorization") String token + @Query("user0-id") String myId, + @Query("user1-id") String partnerId, + @Query("token") String token ); //チャットルームを探す - @GET("foundChatroom") + @GET("chat-rooms") Call getMyChatroom( - @Query("EnterUserId") String userId - + @Query("user0-id") String userId, + @Query("token") String token ); // メッセージ送信 - @POST("sendMessage") + @POST("chat-rooms/{chatroom-id}/{user-id}/message") Call sendMessage( - @Header("Authorization") String token, - @Query("chatroomId") String chatroomId, - @Query("senderId") String senderId, - @Query("content") String content + @Query("token") String token, + @Query("chatroom-id") String chatroomId, + @Query("user-id") String senderId, + @Query("message") String content ); // メッセージ一覧取得 - @GET("getMessages") + @GET("chat-rooms/{chat-room-id}/{user-id}") Call> getMessages( - @Header("Authorization") String token, - @Query("chatroomId") String chatroomId, - @Query("partnerId") String partnerId + @Query("token") String token, + @Query("chat-room-id") String chatroomId, + @Query("user-id") String partnerId ); // チャットルーム削除 - @DELETE("destroyChatroom") + @DELETE("chat-rooms/{chatroom-id}/{user-id}") Call destroyChatroom( - @Header("Authorization") String token, - @Query("chatroomId") String chatroomId, - @Query("userId") String userId + @Query("token") String token, + @Query("chatroom-id") String chatroomId, + @Query("user-id") String userId ); } diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModel.java index 1cf6c18..76fef14 100644 --- a/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModel.java +++ b/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModel.java @@ -8,6 +8,8 @@ import com.example.tampopo_client.models.ChatMessage; import com.example.tampopo_client.models.Chatroom; import com.example.tampopo_client.resources.ChatroomResource; + +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -27,11 +29,10 @@ private final MutableLiveData> chatMessages = new MutableLiveData<>(new ArrayList<>()); private final MutableLiveData latestMessage = new MutableLiveData<>(); private final MutableLiveData chatroomClosed = new MutableLiveData<>(); - private final HashMap> chatFriendToFriendLiveData = new HashMap<>(); // 通話中(リアルタイム監視用) private final MutableLiveData chatFriendToMeLiveData = new MutableLiveData<>(); - private final MutableLiveData chatToFriendLiveData = new MutableLiveData<>(); + // ===== 以下は追加部分(Handlerループ) ===== private final Handler handler = new Handler(Looper.getMainLooper()); @@ -57,7 +58,7 @@ this.chatroomResource = retrofit.create(ChatroomResource.class); } - public ChatViewModel(String userId, String token,String chatroomId) { + public ChatViewModel(String userId, String token, String chatroomId) { this.userId = userId; this.token = token; this.chatroomId = chatroomId; @@ -81,52 +82,81 @@ notificationListeners.forEach(NotificationListener::onNotificationReceived); }, 10_000); // 10秒後に通知 } - foundChatroom(userId); + foundChatroom(userId,token); loadLatestMessage(chatroomId, userId, token); }; } // getter - public MutableLiveData getChatroomIdLiveData() { return chatroomIdLiveData; } - public MutableLiveData> getChatMessages() { return chatMessages; } - public MutableLiveData getLatestMessageLiveData() { return latestMessage; } - public MutableLiveData getChatroomClosed() { return chatroomClosed; } - public MutableLiveData getChatFriendToMeLiveData() { return chatFriendToMeLiveData; } - public MutableLiveData getChatToFriendLiveData() { return chatToFriendLiveData; } + public MutableLiveData getChatroomIdLiveData() { + return chatroomIdLiveData; + } + + public MutableLiveData> getChatMessages() { + return chatMessages; + } + + public MutableLiveData getLatestMessageLiveData() { + return latestMessage; + } + + public MutableLiveData getChatroomClosed() { + return chatroomClosed; + } + + public MutableLiveData getChatFriendToMeLiveData() { + return chatFriendToMeLiveData; + } + + // =============================== // 1. チャットルームに入る(かける側) // =============================== - public void enterChatroom(String myId, String partnerId, String token) { - Call call = chatroomResource.enterChatroom(myId, partnerId, token); - call.enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - chatroomIdLiveData.setValue(response.body().getChatroomId()); - Log.d("ChatVM", "enterChatroom success → chatroomId: " + response.body().getChatroomId()); - } + public String enterChatroom(String user0Id, String user1Id, String token) { + Call call = chatroomResource.enterChatroom(user0Id, user1Id, token); + try { + Response response = call.execute(); + if (response.isSuccessful() && response.body() != null) { + return response.body().getChatRoomId(); + } else { + return null; } - - @Override - public void onFailure(Call call, Throwable t) { - Log.e("ChatVM", "enterChatroom error: " + t.getMessage()); - } - }); + } catch (IOException e) { + throw new RuntimeException(e); + } +// call.enqueue(new Callback() { +// @Override +// public void onResponse(Call call, Response response) { +// if (response.isSuccessful() && response.body() != null) { +// chatroomIdLiveData.setValue(response.body().getChatroomId()); +// Log.d("ChatVM", "enterChatroom success → chatroomId: " + response.body().getChatroomId()); +// } +// } +// +// @Override +// public void onFailure(Call call, Throwable t) { +// Log.e("ChatVM", "enterChatroom error: " + t.getMessage()); +// } +// }); } // 1.5 自分がchatroomに入っているのか確認する - public void foundChatroom(String userId) { - Call call = chatroomResource.getMyChatroom(userId); + public void foundChatroom(String userId, String token) { + Call call = chatroomResource.getMyChatroom(userId, token); call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { if (response.isSuccessful() && response.body() != null) { Chatroom chatroom = response.body(); - chatroomIdLiveData.setValue(chatroom.getChatroomId()); - chatFriendToMeLiveData.setValue(chatroom.getPartnerUserId()); + chatroomIdLiveData.setValue(chatroom.getChatRoomId()); + chatFriendToMeLiveData.setValue( + userId.equals(chatroom.getUser0Id()) + ? chatroom.getUser1Id() + : chatroom.getUser0Id() + ); } else { chatroomIdLiveData.setValue(null); chatroomClosed.setValue(true); @@ -140,46 +170,7 @@ }); } - // =============================== - // 1.55 現在通話中のペアを確認 - // =============================== - public void fetchActiveChatPair(String userId, String token) { - Call call = chatroomResource.getMyChatroom(userId); - call.enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - Chatroom activeRoom = response.body(); - chatroomIdLiveData.setValue(activeRoom.getChatroomId()); - String user1 = activeRoom.getUser1Id(); - String user2 = activeRoom.getUser2Id(); - - // ログインユーザーが user1 の場合 - if (userId.equals(user1)) { - chatFriendToMeLiveData.setValue(user2); // もう一方のユーザーを LiveData にセット - // HashMap にもセット - chatFriendToFriendLiveData.put(userId, new MutableLiveData<>(user2)); - } - // ログインユーザーが user2 の場合 - else if (userId.equals(user2)) { - chatToFriendLiveData.setValue(user1); // もう一方のユーザーを LiveData にセット - chatFriendToFriendLiveData.put(userId, new MutableLiveData<>(user1)); - } - - Log.d("ChatVM", "Active pair found: " + user1 + " ↔ " + user2); - } else { - chatroomIdLiveData.setValue(null); - chatroomClosed.setValue(true); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.e("ChatVM", "fetchActiveChatPair error: " + t.getMessage()); - } - }); - } // =============================== @@ -247,6 +238,7 @@ } // ===== ここから Handlerループ部分をそのまま追記 ===== + /** * 10秒ごとにサーバー確認を行う */ @@ -277,3 +269,4 @@ isChecking = false; } } +// \ No newline at end of file diff --git a/app/src/main/java/com/example/tampopo_client/views/ChatActivity.java b/app/src/main/java/com/example/tampopo_client/views/ChatActivity.java index 3e43680..48ac410 100644 --- a/app/src/main/java/com/example/tampopo_client/views/ChatActivity.java +++ b/app/src/main/java/com/example/tampopo_client/views/ChatActivity.java @@ -97,7 +97,7 @@ String senderId = tampopo.getUserId(); String token = tampopo.getToken(); String chatroomId = tampopo.getChatroomId(); - chatroomViewModel.sendMessage(chatroomId, senderId, senderText, token); + chatroomViewModel.sendMessage(chatroomId, senderId,senderText, token); senderMessage.setText(senderText);//自分のメッセージを送信欄に表示 } } @@ -136,3 +136,4 @@ } } +// \ No newline at end of file diff --git a/app/src/main/java/com/example/tampopo_client/views/FriendIconView.java b/app/src/main/java/com/example/tampopo_client/views/FriendIconView.java index 696407e..e4c197e 100644 --- a/app/src/main/java/com/example/tampopo_client/views/FriendIconView.java +++ b/app/src/main/java/com/example/tampopo_client/views/FriendIconView.java @@ -30,34 +30,29 @@ private TextView mFriendNickname; private ImageView mFriendChatNotification; private boolean chatNotification = false; - private String friendActivity; private String friendUserId; + private String friendUserNickname; private ChatViewModel chatViewModel; - // TODO: CHANGE //ActivityLiveData private final Observer> activitiesObserver = new Observer>() { @Override public void onChanged(List activityList) { if (activityList != null && !activityList.isEmpty()) { Activity act = activityList.get(0); - friendActivity = act.getText(); - setComment(act.getUserId()); + setComment(act.getText()); } } }; - //userLiveData - private final Observer userObserver = new Observer() { - @Override - public void onChanged(String user) { - } - }; - //chatLiveData private final Observer chatObserver = new Observer() { @Override - public void onChanged(String chat) { + public void onChanged(String fromUserId) { + if (friendUserId.equals(fromUserId)) { + chatNotification = true; + mFriendChatNotification.setVisibility(View.VISIBLE); + } } }; @@ -69,9 +64,10 @@ return chatObserver; } - public FriendIconView(Context context, String friendUserId, ChatViewModel chatViewModel) { + public FriendIconView(Context context, String friendUserId, String friendUserNickname, ChatViewModel chatViewModel) { this(context); this.friendUserId = friendUserId; + this.friendUserNickname = friendUserNickname; this.chatViewModel = chatViewModel; init(null, 0); } @@ -102,73 +98,106 @@ mFriendIcon = findViewById(R.id.friend_icon); mFriendChatNotification = findViewById(R.id.chat_notification); - //true(チャット通知が来た時)なら表示 - if (chatNotification) { - mFriendChatNotification.setVisibility(View.VISIBLE); - } - //false(チャット通知が来ていない)なら非表示 - else { - mFriendChatNotification.setVisibility(View.GONE); - } - //iconを押したらチャットを始めることができる(チャットのダイアログができたらFriendActivityを変更) mFriendIcon.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { + //通話に出る場合 if (chatNotification) { - Context ctx = getContext(); - Intent intent = new Intent(ctx, ChatActivity.class); - ctx.startActivity(intent); - mFriendChatNotification.setVisibility(View.GONE); - } else { - // 通話をかける場合 - showCallRequestDialog(getContext(), FriendIconView.this.friendUserId); + answeringCallDialog(getContext(), FriendIconView.this.friendUserNickname); + } // 通話をかける場合 + else if (!chatNotification) { + showCallRequestDialog(getContext(), FriendIconView.this.friendUserNickname); } } }); } - public void showCallRequestDialog(Context context, String fromUserName) { - Dialog dialog = new Dialog(context); - dialog.setContentView(R.layout.dialog_chat_receved); - dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent); - dialog.getWindow().setDimAmount(0.5f); + //通話に出る際のダイアログの表示 + public void answeringCallDialog(Context context, String fromUserNickname) { + Dialog fromDialog = new Dialog(context); + fromDialog.setContentView(R.layout.dialog_chat_receved); + fromDialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent); + fromDialog.getWindow().setDimAmount(0.5f); // メッセージテキスト - TextView tvMessage = dialog.findViewById(R.id.tv_message); - tvMessage.setText(fromUserName + " さんと通話を開始しますか?"); + TextView tvMessage = fromDialog.findViewById(R.id.tv_message); + tvMessage.setText(fromUserNickname + " さんから通話リクエストが届いています。\n通話を開始しますか?"); // 開始ボタン - Button btnStart = dialog.findViewById(R.id.btn_start); + Button btnStart = fromDialog.findViewById(R.id.btn_start); btnStart.setOnClickListener(v -> { Toast.makeText(context, "通話を開始しました", Toast.LENGTH_SHORT).show(); - dialog.dismiss(); + fromDialog.dismiss(); + mFriendChatNotification.setVisibility(View.GONE);//赤丸を消す + chatNotification = false; // 通話を開始する Tampopo tampopo = (Tampopo) ((MainActivity) getContext()).getApplication(); // String chatroomId = chatViewModel.enterChatroom(tampopo.getUserId(), friendUserId, tampopo.getToken()); + tampopo.setChatFriendId(friendUserId); // ChatActivityに画面遷移する Context ctx = getContext(); Intent intent = new Intent(ctx, ChatActivity.class); - intent.putExtra("friendId", friendUserId); -// intent.putExtra("chatroomId", chatroomId); - ctx.startActivity(intent); }); // キャンセルボタン - Button btnCancel = dialog.findViewById(R.id.btn_cancel); - btnCancel.setOnClickListener(v -> dialog.dismiss()); + Button btnCancel = fromDialog.findViewById(R.id.btn_cancel); + btnCancel.setOnClickListener(v -> fromDialog.dismiss()); - dialog.show(); + fromDialog.show(); } + //通話をかける際のダイアログの表示 + public void showCallRequestDialog(Context context, String toUserNickname) { + Dialog toDialog = new Dialog(context); + toDialog.setContentView(R.layout.dialog_chat_receved); + toDialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent); + toDialog.getWindow().setDimAmount(0.5f); + + // メッセージテキスト + TextView tvMessage = toDialog.findViewById(R.id.tv_message); + tvMessage.setText(toUserNickname + " さんと通話を開始しますか?"); + + // 開始ボタン + Button btnStart = toDialog.findViewById(R.id.btn_start); + btnStart.setOnClickListener(v -> { + Toast.makeText(context, "通話を開始しました", Toast.LENGTH_SHORT).show(); + toDialog.dismiss(); + + // 通話を開始する + Tampopo tampopo = (Tampopo) ((MainActivity) getContext()).getApplication(); + new Thread(new Runnable() { + @Override + public void run() { + String chatroomId = chatViewModel.enterChatroom(tampopo.getUserId(), friendUserId, tampopo.getToken()); + tampopo.setChatroomId(chatroomId); + tampopo.setChatFriendId(friendUserId); + } + }).start(); + + // ChatActivityに画面遷移する + Context ctx = getContext(); + Intent intent = new Intent(ctx, ChatActivity.class); + ctx.startActivity(intent); + }); + + // キャンセルボタン + Button btnCancel = toDialog.findViewById(R.id.btn_cancel); + btnCancel.setOnClickListener(v -> toDialog.dismiss()); + + toDialog.show(); + } + + //変更されたニックネームをセット public void setNickname(String nickname) { if (mFriendNickname != null) { mFriendNickname.setText(nickname); } } + //アクティビティの背景(吹き出し) public void setImageResource(int resId) { if (mFriendIcon != null) { mFriendIcon.setImageResource(resId); @@ -179,6 +208,7 @@ return mFriendIcon; } + //アクティビティをセット public void setComment(String comment) { if (mFriendComment != null) { int comment_length = comment.length(); @@ -193,21 +223,6 @@ } } -// public void setActivityLiveDataObserver(String uid, ActivityViewModel viewModel){ -// activityObserver = new Observer>() { - - // TODO: CHANGE -// @Override -// public void onChanged(List activityList) { -// if (activityList != null && !activityList.isEmpty()) { -// Activity act = activityList.get(0); -// friendActivity = act.getText(); -// setAccount(act.getUserId()); -// } -// } -// }; -// viewModel.getActivitiesLiveDataFromUserId(uid).observeForever(activityObserver); -// } /** * FriendIconViewのアイコン画像を更新する @@ -218,23 +233,5 @@ Glide.with(getContext()).load(iconUrl).into(getImageView()); } - //uidを引数にカスタムビューにニックネーム,コメント,アイコンをセットする -// public void setAccount(String uid, String iconUrl) { -// this.userId = uid; -// setNickname("nitta"); -// //String imageUrl = "http://nitta-lab-www.is.konan-u.ac.jp/tampopo-data/icon" + uid + ".jpg"; -// Glide.with(getContext()).load(iconUrl).into(getImageView()); -// } - public void setChatNotification(boolean chat) { - //チャットを終了するときのonclickで一緒にsetChatNotification(false)もする(アイコン周りの赤丸を消す) - //true(チャット通知が来た時)なら表示 - if (chat) { - mFriendChatNotification.setVisibility(View.VISIBLE); - } - //false(チャット通知が来ていない)なら非表示 - else { - mFriendChatNotification.setVisibility(View.GONE); - } - } } diff --git a/app/src/main/java/com/example/tampopo_client/views/MainActivity.java b/app/src/main/java/com/example/tampopo_client/views/MainActivity.java index f2fa84a..a477013 100644 --- a/app/src/main/java/com/example/tampopo_client/views/MainActivity.java +++ b/app/src/main/java/com/example/tampopo_client/views/MainActivity.java @@ -8,6 +8,8 @@ import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodManager; @@ -44,13 +46,21 @@ import com.google.android.material.imageview.ShapeableImageView; import com.example.tampopo_client.viewmodels.ActivityViewModelFactory; import com.example.tampopo_client.viewmodels.ChatViewModel; +import com.example.tampopo_client.viewmodels.ChatViewModelFactory; import com.example.tampopo_client.viewmodels.NotificationListener; +import com.example.tampopo_client.viewmodels.UserViewModel; +import com.google.android.material.imageview.ShapeableImageView; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import android.util.TypedValue; + +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.constraintlayout.widget.ConstraintSet; + public class MainActivity extends AppCompatActivity implements NotificationListener { private EditText editMessage; @@ -62,6 +72,9 @@ private String[] words = {"ひまnow", "あそぼ!", "そろそろ会いたない〜?", "勉強なう", "電話しよ~", "お風呂入ってくる~", "今暇だよー!", "いそがしい~!!"}; private Button openDialogButton; private Map userViews = new HashMap<>(); + private int[] marginTopInDp = {90, 100, 300, 450, 480, 310, 1000}; + private int[] marginStartInDp = {0, 250, 0, 90, 200, 280, 1000}; + private int i = 0; ActivityViewModel activityViewModel; UserViewModel userViewModel; @@ -72,7 +85,6 @@ private final List recentUpdatedFriends = new ArrayList<>(); // 最新6人 - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -101,8 +113,6 @@ // TODO: CHANGE userViewModel = new ViewModelProvider(this).get(UserViewModel.class); - -// handleIncomingIntent(getIntent()); //メイン画面からフレンド一覧画面への遷移 ImageButton friendButton = (ImageButton) findViewById(R.id.friend); friendButton.setOnClickListener(new View.OnClickListener() { @@ -124,17 +134,6 @@ ChatViewModelFactory factory1 = new ChatViewModelFactory(tampopo.getUserId(), tampopo.getToken(), tampopo.getChatroomId()); chatViewModel = new ViewModelProvider(this, factory1).get(ChatViewModel.class); -// MutableLiveData>friendUserIdsLiveDate = activityViewModel.getFriendUserIdsLiveData(); -// friendUserIdsLiveDate.observe(this, new Observer>() { -// @Override -// public void onChanged(List friendLive) { -// if(friendLive != null){ -// friendIds = friendLive; -// updateActivityView(activityViewModel.getActivitiesLiveData().getValue()); -// } -// } -// }); - MutableLiveData> friendsLiveData = activityViewModel.getFriendUserIdsLiveData(); friendsLiveData.observe(this, new Observer>() { @@ -142,79 +141,90 @@ public void onChanged(List friends) { // フレンドの追加と削除 updateActivityView(friends); + + for (String friendId : userViews.keySet()) { + final String updateFriendId = friendId; + MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId); + //MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId); + + FriendIconView friendView = userViews.get(friendId); + if (friendView == null) continue; + + activitiesLiveData.observeForever(new Observer>() { + @Override + public void onChanged(List activities) { + // 更新したフレンドの再登場,更新してないフレンドの退場 + //更新した人を見つけてFriendIconViewを呼び出して、 + FriendIconView userView = userViews.get(updateFriendId); + if (userView != null && activities != null && !activities.isEmpty()) { + Activity latest = activities.get(activities.size() - 1); + String updateFriendId = latest.getUserId(); + } + //フレンドの位置決め + // 最新更新フレンドをリストに追加(最大6人保持) + List list = activityViewModel.getSortedFriendUserIds(); + int size = list.size(); + List latestSix = list.subList(Math.max(size - 6, 0), size); + + synchronized (recentUpdatedFriends) { + if (latestSix.contains(updateFriendId)) { + recentUpdatedFriends.remove(updateFriendId); + recentUpdatedFriends.add(0, updateFriendId); + if (recentUpdatedFriends.size() > 6) { + recentUpdatedFriends.remove(recentUpdatedFriends.size() - 1); + } + } + } + + } + }); + } } }); - for (String friendId: userViews.keySet()) { - final String updateFriendId = friendId; - MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId); - //MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId); - - FriendIconView friendView = userViews.get(friendId); - if(friendView == null) continue; - //activitiesLiveData.observeForever(friendView); - activitiesLiveData.observeForever(new Observer>() { - @Override - public void onChanged(List activities) { - // 更新したフレンドの再登場,更新してないフレンドの退場」 - //更新した人を見つけてFriendIconViewを呼び出して、 - FriendIconView userView = userViews.get(updateFriendId); - if (userView != null && activities != null && !activities.isEmpty()) { - Activity latest = activities.get(activities.size() - 1); - userView.setComment(latest.getText()); - } - //アイコンとニックネーム情報をとってくる - new Thread(() -> { - String nickname = userViewModel.getNickname(updateFriendId); - String iconUrl = userViewModel.getIcon(updateFriendId); - - runOnUiThread(() -> { - if (nickname != null && !nickname.isEmpty()) { - userView.setNickname(nickname); - } else { - userView.setNickname(updateFriendId); - } - -// if (iconUrl != null && !iconUrl.isEmpty()) { -// userView.setIconUrl(iconUrl); -// } else { -// userView.setIconUrl("http://nitta-lab-www.is.konan-u.ac.jp/tampopo/images/default_icon.png"); +// for (String friendId : userViews.keySet()) { +// final String updateFriendId = friendId; +// MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId); +// //MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId); +// +// FriendIconView friendView = userViews.get(friendId); +// if (friendView == null) continue; +// +// activitiesLiveData.observeForever(new Observer>() { +// @Override +// public void onChanged(List activities) { +// // 更新したフレンドの再登場,更新してないフレンドの退場 +// //更新した人を見つけてFriendIconViewを呼び出して、 +// FriendIconView userView = userViews.get(updateFriendId); +// if (userView != null && activities != null && !activities.isEmpty()) { +// Activity latest = activities.get(activities.size() - 1); +// String updateFriendId = latest.getUserId(); +// } +// //フレンドの位置決め +// // 最新更新フレンドをリストに追加(最大6人保持) +// List list = activityViewModel.getSortedFriendUserIds(); +// int size = list.size(); +// List latestSix = list.subList(Math.max(size - 6, 0), size); +// +// synchronized (recentUpdatedFriends) { +// if (latestSix.contains(updateFriendId)) { +// recentUpdatedFriends.remove(updateFriendId); +// recentUpdatedFriends.add(0, updateFriendId); +// if (recentUpdatedFriends.size() > 6) { +// recentUpdatedFriends.remove(recentUpdatedFriends.size() - 1); // } - }); - }).start(); - //フレンドの位置決め - // 最新更新フレンドをリストに追加(最大6人保持) - synchronized (recentUpdatedFriends) { - // すでに存在する場合は削除して再追加(重複防止) - recentUpdatedFriends.remove(updateFriendId); - // 先頭に追加(最近更新した人ほど前) - recentUpdatedFriends.add(0, updateFriendId); - - // 6人を超えたら古いものを削除 - if (recentUpdatedFriends.size() > 6) { - recentUpdatedFriends.remove(recentUpdatedFriends.size() - 1); - } - } - - } - }); - //activitiesLiveData.observe(this, userViews.get(friendId)); - } - - //メイン画面から通知一覧画面への遷移 -// ImageButton notificationButton = (ImageButton)findViewById(R.id.notification); -// notificationButton.setOnClickListener(new View.OnClickListener() { -// public void onClick(View v) { -// Intent intent = new Intent(MainActivity.this,NotificationActivity. class); -// startActivity(intent); -// } -// }); +// } +// } +// +// } +// }); +// } //メイン画面から設定画面への遷移 - ImageButton settingButton = (ImageButton)findViewById(R.id.setting); + ImageButton settingButton = (ImageButton) findViewById(R.id.setting); settingButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - Intent intent = new Intent(MainActivity.this,SettingActivity. class); + Intent intent = new Intent(MainActivity.this, SettingActivity.class); startActivity(intent); } }); @@ -225,24 +235,6 @@ openDialogButton = findViewById(R.id.openDialogButton); openDialogButton.setOnClickListener(v -> showInputDialog()); - // 仮データを作る(ユーザID、コメント) -// List mockActivities = new ArrayList<>(); -// mockActivities.add(new Activity("user01", "act01","ひま〜", "2025-09-25 10:00" )); -// mockActivities.add(new Activity("user02", "act02","勉強してるよ", "2025-09-25 10:01")); -// mockActivities.add(new Activity("user03", "act03","ねむい〜", "2025-09-25 10:02")); - - - // 表示を更新 -// updateActivityView(mockActivities); - - // 疑似通知ボタン chat申請後ダイアログを表示するため、それの疑似的な申請コード - //まだ動くかわからない - //Button testNotificationButton = findViewById(R.id.openDialogButton); // 既存のボタンを利用 - //testNotificationButton.setOnClickListener(v -> { - // 本来は通知を受信したタイミングで呼ばれる - // showCallRequestDialog(MainActivity.this, "user01"); - //}); - } @Override @@ -351,94 +343,93 @@ } private void updateActivityView(List friends) { - //TextView comment = this.findViewById(R.id.friend01_comment); - //for (Activity ac: activities.values()) { - // comment.setText(ac.getText()); - //} - ///natty ユーザごとにコメントの更新をする LinearLayout messageList = findViewById(R.id.messageList); + ConstraintLayout layout = findViewById(R.id.main); + i = 0; for (String friendId : friends) { -// String friendId = entry.getUserId(); -// Activity activity = entry; - FriendIconView userView = userViews.get(friendId); MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(friendId); if (userView == null) { // 新しいユーザなので、アイコン+コメントを作成 - FriendIconView container = new FriendIconView(this); - container.setPadding(16, 16, 16, 16); + //FriendIconView container = new FriendIconView(this); - // ユーザのアイコン(固定) - ShapeableImageView iconView = new ShapeableImageView(this); - iconView.setLayoutParams(new LinearLayout.LayoutParams(100, 100)); - iconView.setScaleType(ImageView.ScaleType.CENTER_CROP); - iconView.setStrokeColor(ContextCompat.getColorStateList(this, R.color.red)); - iconView.setStrokeWidth(2f); - iconView.setShapeAppearanceModel( - iconView.getShapeAppearanceModel().toBuilder() - .setAllCornerSizes(50) // 丸く - .build() - ); - // ユーザIDに応じてアイコンリソースを決定(仮にハードコード or マッピング) - iconView.setImageResource(getUserIconResource(friendId)); // ←ここがポイント + new Thread(new Runnable() { + @Override + public void run() { + FriendIconView container = new FriendIconView(MainActivity.this, friendId, userViewModel.getNickname(friendId), chatViewModel); - // コメント部分 -// TextView commentView = new TextView(this); -// commentView.setTextSize(16); -// commentView.setPadding(16, 0, 0, 0); -// commentView.setText(activity.getText()); + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + @Override + public void run() { + container.setPadding(16, 16, 16, 16); + container.setId(View.generateViewId()); + +// // ユーザのアイコン(固定) +// ShapeableImageView iconView = new ShapeableImageView(MainActivity.this); +// iconView.setLayoutParams(new LinearLayout.LayoutParams(100, 100)); +// iconView.setScaleType(ImageView.ScaleType.CENTER_CROP); +// iconView.setStrokeColor(ContextCompat.getColorStateList(MainActivity.this, R.color.red)); +// iconView.setStrokeWidth(2f); +// iconView.setShapeAppearanceModel( +// iconView.getShapeAppearanceModel().toBuilder() +// .setAllCornerSizes(50) // 丸く +// .build() +// ); + ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams( + ConstraintLayout.LayoutParams.WRAP_CONTENT, + ConstraintLayout.LayoutParams.WRAP_CONTENT + ); + container.setLayoutParams(params); + layout.addView(container); // -// // コンテナに追加 -// container.addView(iconView); -// container.addView(commentView); +// // ユーザIDに応じてアイコンリソースを決定(仮にハードコード or マッピング) +// iconView.setImageResource(getUserIconResource(friendId)); // ←ここがポイント - // Mapに登録、画面に追加 - userViews.put(friendId, container); - messageList.addView(container); + // Mapに登録、画面に追加 + userViews.put(friendId, container); +// userView = container; +// messageList.addView(container); - // TODO: CHANGE - activitiesLiveData.observeForever(container.getActivitiesObserver()); + ConstraintSet set = new ConstraintSet(); + set.clone(layout); + int marginTopInPx = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + marginTopInDp[i], + getResources().getDisplayMetrics() + ); + int marginStartInPx = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + marginStartInDp[i], + getResources().getDisplayMetrics() + ); -// } else { -// // 既に表示されている → コメントだけ更新 -// TextView commentView = (TextView) ((LinearLayout) userView).getChildAt(1); -// commentView.setText(activity.getText()); -// } + set.connect(container.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, marginTopInPx); + set.connect(container.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, marginStartInPx); + + set.applyTo(layout); + + if (i < 6) { + i++; + } + + // TODO: CHANGE + activitiesLiveData.observeForever(container.getActivitiesObserver()); + } + }); + } + }).start(); } } - } -// if (activities == null || friendIds == null) return; -// -// messageList.removeAllViews(); // 表示をリセット -// -// for (String userId : friendIds) { -// Activity activity = activities.get(userId); -// if (activity != null) { -// TextView textView = new TextView(this); -// textView.setText(activity.getText()); -// textView.setTextSize(16); -// textView.setPadding(16, 16, 16, 16); -// // 必要に応じてユーザー名なども表示できる -// messageList.addView(textView); -// } -// } - - //natty - //通知が来たときに赤丸をつける - //通知はまだできてないからいったん赤丸を表示させるっていうの書く - //この下のコードが赤丸がつくコード - //iconView.setStrokeColor(ContextCompat.getColorStateList(this, R.color.red)); //プッシュ通知 private void showChatNotification(String friendName) { -// NotificationManager notificationManager = -// (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); String channelId = "chat_channel"; @@ -471,131 +462,17 @@ 1001 ); } -// ShapeableImageView iconView = new ShapeableImageView(this); -// iconView.setStrokeColor(ContextCompat.getColorStateList(this, R.color.black)); - } else { Log.d("NotificationTest", "notify() 呼ばれた!!"); notificationManager.notify(0, builder.build()); } - - } -// private static final int REQUEST_CODE_POST_NOTIFICATIONS = 1001; -// -// // 通知権限をチェックしてリクエストする -// private void checkAndRequestNotificationPermission() { -// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { -// // Android 13以上 → POST_NOTIFICATIONS の確認 -// if (ContextCompat.checkSelfPermission( -// this, -// android.Manifest.permission.POST_NOTIFICATIONS -// ) != PackageManager.PERMISSION_GRANTED) { -// -// ActivityCompat.requestPermissions( -// this, -// new String[]{android.Manifest.permission.POST_NOTIFICATIONS}, -// REQUEST_CODE_POST_NOTIFICATIONS -// ); -// } -// } else { -// // Android 12以下 → 権限は存在しないので説明だけ -// Toast.makeText(this, -// "通知を受け取るには端末の設定から通知を有効にしてください", -// Toast.LENGTH_LONG).show(); -// } -// } -// @Override -// public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { -// super.onRequestPermissionsResult(requestCode, permissions, grantResults); -// -// if (requestCode == REQUEST_CODE_POST_NOTIFICATIONS) { -// if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { -// Toast.makeText(this, "通知が許可されました", Toast.LENGTH_SHORT).show(); -// } else { -// Toast.makeText(this, "通知が拒否されました。設定から有効にできます", Toast.LENGTH_LONG).show(); -// } -// } -// } - private void highlightUserIcon(String userId) { - runOnUiThread(() -> { - FriendIconView container = userViews.get(userId); - if (container != null && container.getChildCount() > 0) { - View v = container.getChildAt(0); - if (v instanceof ShapeableImageView) { - ShapeableImageView icon = (ShapeableImageView) v; - icon.setStrokeColor(ContextCompat.getColorStateList(this, R.color.red)); - icon.setStrokeWidth(6f); // 太めにして目立たせる - } - } - }); } - private void clearUserIconHighlight(String userId) { - runOnUiThread(() -> { - FriendIconView container = userViews.get(userId); - if (container != null && container.getChildCount() > 0) { - View v = container.getChildAt(0); - if (v instanceof ShapeableImageView) { - ShapeableImageView icon = (ShapeableImageView) v; - icon.setStrokeWidth(0f); // 初期状態(枠なし)に戻す - } - } - }); - } - - - - //通話が来たときのダイアログ - // 通話リクエストを受け取った時に呼び出すダイアログ - public void showCallRequestDialog(Context context, String fromUserName) { - - Dialog dialog = new Dialog(context); - dialog.setContentView(R.layout.dialog_chat_receved); - dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent); - dialog.getWindow().setDimAmount(0.5f); - - // メッセージテキスト - TextView tvMessage = dialog.findViewById(R.id.tv_message); - tvMessage.setText(fromUserName + " さんから通話リクエストが届いています。\n通話を開始しますか?"); - - // 開始ボタン - Button btnStart = dialog.findViewById(R.id.btn_start); - btnStart.setOnClickListener(v -> { - Toast.makeText(context, "通話を開始しました", Toast.LENGTH_SHORT).show(); - dialog.dismiss(); - // TODO: 実際の通話開始処理をここに書く - }); - - // キャンセルボタン - Button btnCancel = dialog.findViewById(R.id.btn_cancel); - btnCancel.setOnClickListener(v -> dialog.dismiss()); - - dialog.show(); - } -//通知を受信したときのダイアログ これが動いてます + //通知を受信したときのダイアログ これが動いてます //friendName+から通話があります。ってでるから通知が来たときのフレンドを変数に置く必要がある @Override public void onNotificationReceived() { // 通知を受信したときにダイアログを表示 runOnUiThread(() -> showChatNotification("user02")); - // アイコンを赤枠に - //runOnUiThread(() -> highlightUserIcon("user01")); } -// @Override -// protected void onNewIntent(Intent intent) { -// super.onNewIntent(intent); -// setIntent(intent); // 忘れずに更新 -// handleIncomingIntent(intent); -// } - -// private void handleIncomingIntent(Intent intent) { -// if (intent != null && intent.hasExtra("incoming_user_id")) { -// String incomingUserId = intent.getStringExtra("incoming_user_id"); -// if (incomingUserId != null) { -// // userIdからユーザ名を取得する処理を入れてもいいし -// showCallRequestDialog(this, incomingUserId); -// } -// } -// } - } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d02c831..3b1ce58 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -82,34 +82,6 @@ app:layout_constraintVertical_bias="0.38" app:srcCompat="@drawable/comment" /> - - - - - - - \ No newline at end of file