diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 09ad5d2..40840fd 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -61,6 +61,9 @@
+
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 7f183cd..c4d1267 100644
--- a/app/src/main/java/com/example/tampopo_client/Tampopo.java
+++ b/app/src/main/java/com/example/tampopo_client/Tampopo.java
@@ -4,6 +4,10 @@
import android.content.SharedPreferences;
public class Tampopo extends Application {
+ //いらないので下記2つをコメントアウトしました
+ //public String getUserId;
+
+ //public String getToken;
private String token;
private String userId;
private String password;
@@ -52,7 +56,6 @@
}
-
public String getNickname() { return nickname; }
public void setNickname(String nickname) {
diff --git a/app/src/main/java/com/example/tampopo_client/models/Activity.java b/app/src/main/java/com/example/tampopo_client/models/Activity.java
index 7c3d626..6dcf984 100644
--- a/app/src/main/java/com/example/tampopo_client/models/Activity.java
+++ b/app/src/main/java/com/example/tampopo_client/models/Activity.java
@@ -13,6 +13,9 @@
this.updateTime = updateTime;
}
+ public Activity() {
+ }
+
public String getUserId() {
return userId;
}
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 5a08e92..74622ba 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
@@ -2,21 +2,48 @@
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) {
+ public Chatroom(String chatroomId, String user1Id, String user2Id) {
this.chatroomId = chatroomId;
+ this.user1Id = user1Id;
+ this.user2Id = user2Id;
+ }
+
+
+ public Chatroom(String chatroomId,String partnerUserId) {
+ this.chatroomId = chatroomId;
+ this.partnerUserId = partnerUserId;
}
public String getChatroomId() {
return chatroomId;
}
- public String foundChatroomId(){return chatroomId;}
-
public void setChatroomId(String chatroomId) {
this.chatroomId = chatroomId;
}
+ public String getUser1Id() {
+ return user1Id;
+ }
+
+
+
+ public String getUser2Id() {
+ return user2Id;
+ }
+
+
+ public String getPartnerUserId() {
+ return partnerUserId;
+ }
+
+ public void setPartnerUserId(String partnerUserId) {
+ this.partnerUserId = partnerUserId;
+ }
+
}
diff --git a/app/src/main/java/com/example/tampopo_client/models/FriendPair.java b/app/src/main/java/com/example/tampopo_client/models/FriendPair.java
index 4f9c35f..3ba71cd 100644
--- a/app/src/main/java/com/example/tampopo_client/models/FriendPair.java
+++ b/app/src/main/java/com/example/tampopo_client/models/FriendPair.java
@@ -10,6 +10,7 @@
this.user1Id = user1Id;
}
+
public Integer getId() {
return id;
}
diff --git a/app/src/main/java/com/example/tampopo_client/resources/ActivitiesResource.java b/app/src/main/java/com/example/tampopo_client/resources/ActivitiesResource.java
index 7df8292..cef31d5 100644
--- a/app/src/main/java/com/example/tampopo_client/resources/ActivitiesResource.java
+++ b/app/src/main/java/com/example/tampopo_client/resources/ActivitiesResource.java
@@ -2,6 +2,7 @@
import com.example.tampopo_client.models.Activity;
+import java.util.HashMap;
import java.util.List;
import retrofit2.Call;
@@ -15,7 +16,7 @@
public interface ActivitiesResource {
@GET("users/{user_id}/activities")
- Call> getActivities(@Path("user_id") String userId, @Query("filter") String filter);
+ Call> getActivities(@Path("user_id") String userId, @Query("filter") String filter);
@POST("users/{user_id}/activities")
@FormUrlEncoded
@@ -31,8 +32,8 @@
Call getText(@Path("user_id") String userId, @Path("activity_id") String activityId);
@GET("users/{user_id}/activities/{activity_id}/updated-time")
- Call getUpdatedTime(@Path("user_id") String userId, @Path("activity_id") String activityId);
+ Call getUpdatedTime(@Path("user_id") String userId, @Path("activity_id") String activityId);
@GET("users/{user_id}/activities/last-updated-time")
- Call getLastUpdatedTime(@Path("user_id") String userId, @Path("activity_id") String activityId);
+ Call getLastUpdatedTime(@Path("user_id") String userId, @Path("activity_id") String activityId);
}
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 2574364..4384636 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
@@ -27,6 +27,7 @@
@GET("foundChatroom")
Call getMyChatroom(
@Query("EnterUserId") String userId
+
);
diff --git a/app/src/main/java/com/example/tampopo_client/resources/FriendsResource.java b/app/src/main/java/com/example/tampopo_client/resources/FriendsResource.java
index d323d6c..7c91307 100644
--- a/app/src/main/java/com/example/tampopo_client/resources/FriendsResource.java
+++ b/app/src/main/java/com/example/tampopo_client/resources/FriendsResource.java
@@ -2,6 +2,8 @@
import com.example.tampopo_client.models.FriendPair;
+import java.util.List;
+
import retrofit2.Call;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
@@ -20,6 +22,13 @@
@Field("user1-id") String user1Id
);
+// @GET("friends/{pair_id}/")
+// Call getFriend(
+// @Query("token") String token,
+// @Path("pair_id") String pairId
+// );
+
+ //
@GET("friends/{pair_id}/")
Call getFriend(
@Query("token") String token,
@@ -31,4 +40,11 @@
@Query("token") String token,
@Path("pair_id") String pair_id
);
+
+ //新しくサーバーで定義したので追加しました
+ @GET("friends/users/{user-id}")
+ Call> getFriends(
+ @Path("user-id") String userId,
+ @Query("token") String token
+ );
}
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/ActivitiesFetchCallback.java b/app/src/main/java/com/example/tampopo_client/viewmodels/ActivitiesFetchCallback.java
new file mode 100644
index 0000000..ad6ca5f
--- /dev/null
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/ActivitiesFetchCallback.java
@@ -0,0 +1,11 @@
+package com.example.tampopo_client.viewmodels;
+
+import com.example.tampopo_client.models.Activity;
+
+import java.util.List;
+
+public interface ActivitiesFetchCallback {
+ void onSuccess(List activities);
+
+ void onFailure(Throwable throwable);
+}
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/ActivityViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/ActivityViewModel.java
index 2c455f2..3d15caf 100644
--- a/app/src/main/java/com/example/tampopo_client/viewmodels/ActivityViewModel.java
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/ActivityViewModel.java
@@ -9,8 +9,16 @@
import com.example.tampopo_client.resources.ActivitiesResource;
import com.example.tampopo_client.resources.UserResource;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
import retrofit2.Call;
import retrofit2.Callback;
@@ -28,25 +36,37 @@
private final ActivitiesResource activitiesResource;
private final UserResource userResource;
- private final Map>> friendToActivitiesLiveData; // key=userId
- private final MutableLiveData> friendUserIdsLiveData; // フレンドのユーザーIDのリスト
private final MutableLiveData myLatestActivityLiveData; // 自分の最新のアクティビティ
+ private final Map>> friendToActivitiesLiveData; // <フレンドのユーザーID, フレンドのアクティビティのリスト>
+ private final MutableLiveData> friendUserIdsLiveData; // フレンドのユーザーIDのリスト
- private final String userId;
- private final String token;
+ private final String myUserId;
+ private final String myToken;
- public ActivityViewModel(String userId, String token) {
- this.userId = userId;
- this.token = token;
+ private final List userActivityStatusChangeListeners;
+
+ private final List sortedFriendUserIds = new ArrayList<>();
+
+ /**
+ * ActivityのViewModelを作成する。
+ *
+ * @param myUserId 自身のユーザーID
+ * @param myToken 自身の認証用トークン
+ */
+ public ActivityViewModel(String myUserId, String myToken) {
+ this.myUserId = myUserId;
+ this.myToken = myToken;
// Retrofitの初期化
final Retrofit retrofit = new Retrofit.Builder().baseUrl("http://nitta-lab-www.is.konan-u.ac.jp/tampopo/").addConverterFactory(JacksonConverterFactory.create()).build();
activitiesResource = retrofit.create(ActivitiesResource.class);
userResource = retrofit.create(UserResource.class);
- friendToActivitiesLiveData = Map.of();
+ friendToActivitiesLiveData = new HashMap<>();
friendUserIdsLiveData = new MutableLiveData<>(List.of());
- myLatestActivityLiveData = new MutableLiveData<>();
+ myLatestActivityLiveData = new MutableLiveData<>(null);
+
+ userActivityStatusChangeListeners = new ArrayList<>();
}
@Override
@@ -56,23 +76,95 @@
return;
}
- // 最新のアクティビティを取得して更新する
+ // 自分の最新のアクティビティを取得する
+ pullLatestActivity(myUserId, activitiesResource, new ActivityFetchCallback() {
+ @Override
+ public void onSuccess(Activity activity) {
+ Activity prevActivity = myLatestActivityLiveData.getValue();
+
+ // アクティビティが更新されていない場合
+ LocalDateTime now = LocalDateTime.now();
+ LocalDateTime lastUpdatedTime = getDateTimeFromString(activity.getUpdateTime());
+
+ if (now.isAfter(lastUpdatedTime.plusSeconds(5))) {
+ for (UserActivityStatusChangeListener observer : userActivityStatusChangeListeners) {
+ // アクティビティのステータス変更をリスナーに通知する
+ if (activity.equals(prevActivity)) {
+ observer.onUserStatusChanged(myUserId, UserActivityStatusChangeListener.Status.INACTIVE);
+ } else {
+ observer.onUserStatusChanged(myUserId, UserActivityStatusChangeListener.Status.ACTIVE);
+ }
+ }
+ }
+
+ // 自分の新しいアクティビティをLiveDataに反映する
+ myLatestActivityLiveData.postValue(activity);
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ Log.e(ActivityViewModel.class.getSimpleName(), "An error has occurred while fetching my latest activity.");
+ }
+ });
+
+ // 自分のフレンドの最新のアクティビティを取得して更新する
if (friendUserIdsLiveData.isInitialized() && friendUserIdsLiveData.getValue() != null) {
for (String userId : friendUserIdsLiveData.getValue()) {
- pullLatestActivity(userId, activitiesResource, friendToActivitiesLiveData);
+ pullLatestActivity(userId, activitiesResource, new ActivityFetchCallback() {
+ @Override
+ public void onSuccess(Activity activity) {
+ updateFriendToActivitiesLiveData(activity, userId);
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ Log.e(ActivityViewModel.class.getSimpleName(), "An error has occurred while fetching friend's latest activity.", throwable);
+ }
+ });
}
}
- // 最新のフレンドのユーザーIDを取得して更新する
if (friendUserIdsLiveData.isInitialized()) {
- pullLatestFriendUserIds(userId, token);
+ // 最新のフレンドのユーザーIDを取得して更新する
+ // TODO: 適切なコールバックを使う必要あり
+ pullLatestFriendUserIds(myUserId, myToken);
}
-
- // Logging
- Log.d(ActivityViewModel.class.getSimpleName(), "Polling data from the server.");
};
}
+ /**
+ * ユーザIDからそのユーザーのアクティビティのリストのライブデータを取得し、最新のアクティビティに更新する
+ *
+ * @param latestActivity 最新のアクティビティ
+ * @param userId 更新対象のユーザーID
+ */
+ private void updateFriendToActivitiesLiveData(Activity latestActivity, String userId) {
+ if (friendToActivitiesLiveData.get(userId) == null) {
+ friendToActivitiesLiveData.put(userId, new MutableLiveData<>(List.of()));
+ }
+ MutableLiveData> userActivitiesLiveData = friendToActivitiesLiveData.get(userId);
+ assert userActivitiesLiveData != null;
+
+ List userActivities = userActivitiesLiveData.getValue();
+
+ if (userActivities == null || userActivities.isEmpty()) {
+ userActivitiesLiveData.postValue(List.of(latestActivity));
+ } else {
+ if (userActivities.equals(List.of(latestActivity))) {
+ return;
+ }
+
+ userActivitiesLiveData.postValue(List.of(latestActivity));
+ }
+ }
+
+ /**
+ * 自身のアクティビティを新しく作成する
+ *
+ * @param userId 自身のユーザーID
+ * @param token 自身の認証用トークン
+ * @param newActivity 新しいアクティビティのテキスト
+ */
public void createActivity(String userId, String token, String newActivity) {
if (!myLatestActivityLiveData.isInitialized()) {
return;
@@ -85,7 +177,6 @@
if (response.isSuccessful()) {
String createdActivityId = response.body();
- // TODO: 仮作成なので改善したい
Call getActivityCall = activitiesResource.getActivity(userId, createdActivityId);
getActivityCall.enqueue(new Callback() {
@Override
@@ -117,54 +208,47 @@
/**
* 最新のユーザーのアクティビティを取得・更新する
*
- * @param userId 取得対象のユーザーのID
- * @param resource アクティビティのリソース
- * @param friendToActivitiesLiveData フレンドのユーザーIDからアクティビティへの写像のライブデータ
+ * @param userId 取得対象のユーザーのID
+ * @param resource アクティビティのリソース
+ * @param callback アクティビティが取得された後に呼び出されるコールバック
*/
- private void pullLatestActivity(String userId, ActivitiesResource resource, Map>> friendToActivitiesLiveData) {
- Call> fetchActivityCall = resource.getActivities(userId, "LATEST");
- fetchActivityCall.enqueue(new Callback>() {
+ private void pullLatestActivity(String userId, ActivitiesResource resource, ActivityFetchCallback callback) {
+ Call> fetchActivityCall = resource.getActivities(userId, "LATEST");
+ fetchActivityCall.enqueue(new Callback>() {
@Override
- public void onResponse(@NonNull Call> call, @NonNull Response> response) {
+ public void onResponse(@NonNull Call> call, @NonNull Response> response) {
if (response.isSuccessful()) {
- List fetchedActivities = response.body(); // アクティビティが存在しない場合は空のリスト
- if (fetchedActivities == null) {
+ Collection activities = response.body().values(); // アクティビティが存在しない場合は空のリスト
+ if (activities == null || activities.isEmpty()) {
return;
}
- if (friendToActivitiesLiveData.get(userId) == null) {
- friendToActivitiesLiveData.put(userId, new MutableLiveData<>(List.of()));
- }
- MutableLiveData> userActivitiesLiveData = friendToActivitiesLiveData.get(userId);
- assert userActivitiesLiveData != null;
-
- List userActivities = userActivitiesLiveData.getValue();
- if (userActivities == null) {
- return;
- }
- if (fetchedActivities.isEmpty()) {
- return;
- }
-
- if (userActivities.isEmpty()) {
- userActivitiesLiveData.postValue(fetchedActivities);
- } else {
- if (userActivities.equals(fetchedActivities)) {
- return;
- }
- userActivitiesLiveData.postValue(fetchedActivities);
- }
+ Activity latestActivity = activities.iterator().next();
+ callback.onSuccess(latestActivity);
}
}
@Override
- public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
+ public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
Log.e(ActivityViewModel.class.getSimpleName(), "An error has occurred while fetching the latest activity.", t);
+
+ callback.onFailure(t);
}
});
}
/**
+ * String型の日時をLocalDateTime型に変換する
+ *
+ * @param dateTime 変換対象の日時(文字列)
+ * @return 変換後の日時(LocalDateTime)
+ */
+ private static LocalDateTime getDateTimeFromString(String dateTime) {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm");
+ return LocalDateTime.parse(dateTime, formatter);
+ }
+
+ /**
* 最新の自分のフレンドのユーザーIDをすべて取得・更新する。
*
* @param userId 自分のユーザーID
@@ -176,7 +260,29 @@
@Override
public void onResponse(@NonNull Call> call, @NonNull Response> response) {
if (response.isSuccessful()) {
- friendUserIdsLiveData.postValue(response.body());
+
+ // MEMO: 入れ込んだだけ
+ // フレンドのIDをアクティビティ更新順に並べ替える
+ List friendUserIds = friendUserIdsLiveData.getValue();
+ if (friendUserIds == null || !friendUserIds.equals(response.body())) {
+ friendUserIdsLiveData.postValue(response.body());
+ SortedSet friends = new TreeSet<>(new Friend.UpdateTimeComparator());
+
+ assert friendUserIds != null;
+ friendUserIds.forEach(userId -> {
+ List activities = getActivitiesLiveDataFromUserId(userId).getValue();
+ if (activities == null || activities.isEmpty()) {
+ return;
+ }
+
+ Activity latestActivity = activities.get(0);
+ friends.add(new Friend(userId, latestActivity.getUpdateTime()));
+ });
+
+ // 並び替えたフレンドのユーザーIDを順番に格納して更新する
+ sortedFriendUserIds.clear();
+ friends.forEach(friend -> sortedFriendUserIds.add(friend.getUserId()));
+ }
}
}
@@ -191,7 +297,16 @@
return myLatestActivityLiveData;
}
+ /**
+ * ユーザIDからそのユーザーのアクティビティのリストのライブデータを取得する
+ *
+ * @param userId 取得対象のユーザーID
+ * @return 取得対象のユーザーのアクティビティのリストのライブデータ
+ */
public MutableLiveData> getActivitiesLiveDataFromUserId(String userId) {
+ if (!friendToActivitiesLiveData.containsKey(userId)) {
+ friendToActivitiesLiveData.put(userId, new MutableLiveData<>());
+ }
return friendToActivitiesLiveData.get(userId);
}
@@ -199,11 +314,54 @@
return friendUserIdsLiveData;
}
- public String getUserId() {
- return userId;
+ public String getMyUserId() {
+ return myUserId;
}
- public String getToken() {
- return token;
+ public String getMyToken() {
+ return myToken;
+ }
+
+ public List getSortedFriendUserIds() {
+ return sortedFriendUserIds;
+ }
+
+ public void addActivityStatusChangeObserver(UserActivityStatusChangeListener observer) {
+ userActivityStatusChangeListeners.add(observer);
+ }
+
+ public void clearActivityStatusChangeObservers() {
+ userActivityStatusChangeListeners.clear();
+ }
+
+ private static class Friend {
+ private final String userId;
+ private final LocalDateTime latestUpdateTime;
+
+ public Friend(String userId, String latestUpdateTime) {
+ this.userId = userId;
+ this.latestUpdateTime = getDateTimeFromString(latestUpdateTime);
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public LocalDateTime getLatestUpdateTime() {
+ return latestUpdateTime;
+ }
+
+ public static class UpdateTimeComparator implements Comparator {
+ @Override
+ public int compare(Friend o1, Friend o2) {
+ return o1.getLatestUpdateTime().compareTo(o2.getLatestUpdateTime());
+ }
+ }
+ }
+
+ private interface ActivityFetchCallback {
+ void onSuccess(Activity activity);
+
+ void onFailure(Throwable throwable);
}
}
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 0c5a721..1cf6c18 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
@@ -3,46 +3,264 @@
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
-
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+import com.example.tampopo_client.models.ChatMessage;
+import com.example.tampopo_client.models.Chatroom;
+import com.example.tampopo_client.resources.ChatroomResource;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.jackson.JacksonConverterFactory;
public class ChatViewModel extends RealTimeViewModel {
+
+ private final Retrofit retrofit;
+ private final ChatroomResource chatroomResource;
+
+ // --- LiveData ---
+ private final MutableLiveData chatroomIdLiveData = new MutableLiveData<>();
+ 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());
+ private boolean isChecking = false; // 二重起動防止フラグ
+
+
+ // ===============================
+ // 通知・リアルタイム関連
+ // ===============================
private final List notificationListeners = new ArrayList<>();
+ private boolean notificationSent = false; // 一度だけ通知を送るためのフラグ
- //private static final double NOTIFICATION_RECEIVE_PROBABILITY = 0.5;
+ private String userId;
+ private String token;
+ private String chatroomId;
- //natty
- private boolean notificationSent = false; // 一度だけ送信するためのフラグ
+ public ChatViewModel() {
+ this.retrofit = new Retrofit.Builder()
+ .baseUrl("http://nitta-lab-www.is.konan-u.ac.jp/tampopo/")
+ .addConverterFactory(JacksonConverterFactory.create())
+ .build();
+
+ this.chatroomResource = retrofit.create(ChatroomResource.class);
+ }
+
+ public ChatViewModel(String userId, String token,String chatroomId) {
+ this.userId = userId;
+ this.token = token;
+ this.chatroomId = chatroomId;
-// @Override
-// public Runnable onUpdate() {
-// return () -> {
-// // 1% の確率で onNotificationReceived() が呼び出される
-// double borderValue = Math.floor(Math.random() * 100);
-// double currentValue = NOTIFICATION_RECEIVE_PROBABILITY * 100;
-// if (currentValue >= borderValue) {
-// Log.d("ChatViewModel", "Received test notification.");
-// notificationListeners.forEach(listener -> listener.onNotificationReceived());
-// }
-// };
-// }
- //natty
+ this.retrofit = new Retrofit.Builder()
+ .baseUrl("http://nitta-lab-www.is.konan-u.ac.jp/tampopo/")
+ .addConverterFactory(JacksonConverterFactory.create())
+ .build();
+
+ this.chatroomResource = retrofit.create(ChatroomResource.class);
+ }
+
@Override
public Runnable onUpdate() {
return () -> {
if (!notificationSent) {
- // 10秒後に一回だけ通知を送る
- notificationSent = true; // もう送らない
+ notificationSent = true;
new Handler(Looper.getMainLooper()).postDelayed(() -> {
Log.d("ChatViewModel", "Received test notification (after 10s).");
notificationListeners.forEach(NotificationListener::onNotificationReceived);
- }, 10_000); // 10秒(10000ms)
+ }, 10_000); // 10秒後に通知
}
+ foundChatroom(userId);
+ 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; }
+
+ // ===============================
+ // 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());
+ }
+ }
+
+ @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);
+ 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());
+ } else {
+ chatroomIdLiveData.setValue(null);
+ chatroomClosed.setValue(true);
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ Log.e("ChatroomVM", "checkCurrentChatroom error: " + t.getMessage());
+ }
+ });
+ }
+
+ // ===============================
+ // 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());
+ }
+ });
+ }
+
+
+ // ===============================
+ // 2. メッセージ送信
+ // ===============================
+ public void sendMessage(String chatroomId, String senderId, String message, String token) {
+ Call call = chatroomResource.sendMessage(token, chatroomId, senderId, message);
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.isSuccessful() && response.body() != null) {
+ ChatMessage newMessage = response.body();
+ latestMessage.setValue(newMessage);
+ }
+ }
+
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ Log.e("ChatVM", "sendMessage error: " + t.getMessage());
+ }
+ });
+ }
+
+ // ===============================
+ // 3. 最新メッセージ取得
+ // ===============================
+ public void loadLatestMessage(String chatroomId, String userId, String token) {
+ Call> call = chatroomResource.getMessages(token, chatroomId, userId);
+ call.enqueue(new Callback>() {
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ if (response.isSuccessful() && response.body() != null && !response.body().isEmpty()) {
+ latestMessage.setValue(response.body().get(response.body().size() - 1));
+ }
+ }
+
+ @Override
+ public void onFailure(Call> call, Throwable t) {
+ Log.e("ChatVM", "loadLatestMessage error: " + t.getMessage());
+ }
+ });
+ }
+
+ // ===============================
+ // 4. チャットルーム削除
+ // ===============================
+ public void destroyChatroom(String chatroomId, String userId, String token) {
+ Call call = chatroomResource.destroyChatroom(token, chatroomId, userId);
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ chatroomClosed.setValue(true);
+ if (!response.isSuccessful()) {
+ Log.e("ChatVM", "destroyChatroom failed: " + response.code());
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ chatroomClosed.setValue(true);
+ Log.e("ChatVM", "destroyChatroom error: " + t.getMessage());
+ }
+ });
+ }
+
+ // ===== ここから Handlerループ部分をそのまま追記 =====
+ /**
+ * 10秒ごとにサーバー確認を行う
+ */
+ private void startServerCheck() {
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ Log.d("ChatViewModel", "Checking server / Received test notification.");
+ notificationListeners.forEach(NotificationListener::onNotificationReceived);
+ handler.postDelayed(this, 10_000);
+ }
+ }, 10_000);
+ }
+
public void addNotificationListener(NotificationListener listener) {
notificationListeners.add(listener);
}
@@ -50,4 +268,12 @@
public void clearNotificationListener() {
notificationListeners.clear();
}
+
+ /**
+ * 定期確認を止めたい場合に使う
+ */
+ public void stopServerCheck() {
+ handler.removeCallbacksAndMessages(null);
+ isChecking = false;
+ }
}
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModelFactory.java b/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModelFactory.java
new file mode 100644
index 0000000..48d5ce0
--- /dev/null
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModelFactory.java
@@ -0,0 +1,34 @@
+package com.example.tampopo_client.viewmodels;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+
+import java.lang.reflect.InvocationTargetException;
+
+public class ChatViewModelFactory implements ViewModelProvider.Factory {
+ private final String userId;
+ private final String token;
+ private final String chatroomId;
+
+ public ChatViewModelFactory(String userId, String token, String chatroomId) {
+ this.userId = userId;
+ this.token = token;
+ this.chatroomId = chatroomId;
+ }
+
+ @NonNull
+ @Override
+ public T create(@NonNull Class modelClass) {
+ if (modelClass.isAssignableFrom(ChatViewModel.class)) {
+ try {
+ return modelClass.getConstructor(String.class, String.class).newInstance(userId, token);
+ } catch (InvocationTargetException | IllegalAccessException | InstantiationException |
+ NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ throw new IllegalStateException("作成するViewModelが異なります。");
+ }
+}
+
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/ChatroomViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/ChatroomViewModel.java
deleted file mode 100644
index 901b43c..0000000
--- a/app/src/main/java/com/example/tampopo_client/viewmodels/ChatroomViewModel.java
+++ /dev/null
@@ -1,180 +0,0 @@
-package com.example.tampopo_client.viewmodels;
-
-import android.util.Log;
-
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
-
-import com.example.tampopo_client.models.ChatMessage;
-import com.example.tampopo_client.models.Chatroom;
-import com.example.tampopo_client.resources.ChatroomResource;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-import retrofit2.Retrofit;
-import retrofit2.converter.jackson.JacksonConverterFactory;
-
-public class ChatroomViewModel extends ViewModel {
-
- private final Retrofit retrofit;
- private final ChatroomResource chatroomResource;
-
- private final MutableLiveData chatroomId = new MutableLiveData<>();
- private final MutableLiveData> chatMessages = new MutableLiveData<>(new ArrayList<>());
- private final MutableLiveData latestMessage = new MutableLiveData<>();
- private final MutableLiveData chatroomClosed = new MutableLiveData<>();
-
- public ChatroomViewModel() {
- this.retrofit = new Retrofit.Builder()
- .baseUrl("http://nitta-lab-www.is.konan-u.ac.jp/tampopo/")
- .addConverterFactory(JacksonConverterFactory.create())
- .build();
-
- this.chatroomResource = retrofit.create(ChatroomResource.class);
- }
-
- // LiveData getter
- public MutableLiveData getChatroomIdLiveData() {
- return chatroomId;
- }
-
- public MutableLiveData> getChatMessages() {
- return chatMessages;
- }
-
- public MutableLiveData getLatestMessageLiveData() {
- return latestMessage;
- }
-
- public MutableLiveData getChatroomClosed() {
- return chatroomClosed;
- }
-
- // 1. チャットルームに入る(入れる側)
- public void enterChatroom(String myId, String partnerId, String token) {
- //自分のIdと相手のidと自分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) {
- chatroomId.setValue(response.body().getChatroomId());
- }
- }//サーバーからchatroomIdが送られてきてそれを保持する処理
-
- @Override
- public void onFailure(Call call, Throwable t) {
- Log.e("ChatViewModel", "enterChatroom error: " + t.getMessage());
- }
- });
- }
-
- //1.5自分がcahtroomに入っているのかを確認する
- public void foundChatroom(String userId) {
- Call call = chatroomResource.getMyChatroom(userId);
- call.enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) {
- if (response.isSuccessful() && response.body() != null) {
- chatroomId.setValue(response.body().getChatroomId());
- //これがあっているのか確認chatroomIdどんなうごきをするのか確認せよ
- } else {
- chatroomId.setValue(null); // どこにも入っていない場合
- chatroomClosed.setValue(true);
- }
- }
-
- @Override
- public void onFailure(Call call, Throwable t) {
- Log.e("ChatroomVM", "checkCurrentChatroom error: " + t.getMessage());
- }
- });
- }
-
- // 2. メッセージ送信(リアルタイム風)送る側
- //自分のchatはmychatmesaageに変更するかも
- public void sendMessage(String chatroomId, String senderId, String content, String token) {
- //このメソッドは 指定したチャットルーム (chatroomId) に、あるユーザー (senderId) が、入力したメッセージ (message) を、認証トークン (token) を使って送信する役割です。
- Call call = chatroomResource.sendMessage(token, chatroomId, senderId, content);
- //Retrofit を使って 「サーバーのAPIにメッセージ送信リクエストを作る」 メソッド。
- call.enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) {
- if (response.isSuccessful() && response.body() != null) {
- ChatMessage newMessage = response.body();
- // 成功したらそのまま新しいメッセージをUIに流す
-
-// // 既存のメッセージリストを更新
- //受け取る側のコードっぽいので不要だと思ってます理由はnewMessageでUIを表示するのでそれ以外いらない
-// //画面に表示されているメッセージリスト (chatMessages) を取り出し、そこに 新しいメッセージを追加して更新しています。
-// List current = chatMessages.getValue();
-// if (current == null) current = new ArrayList<>();
-
-
- // operationResult は表示不要なので更新しない
- }
- // 失敗した場合も「エラーです」とは出さない(履歴を残さない仕様)
- }
-
- @Override
- public void onFailure(Call call, Throwable t) {
- // ネットワークエラーでも通知はしない(UI上に履歴が残らない通話風チャットだから)
- // 必要なら内部ログにだけ残す
- Log.e("ChatViewModel", "sendMessage error: " + t.getMessage());
- }
- });
- }
-
-
- // 3. 最新メッセージ取得(エラー時はUIに表示しない)受け取る側
- public void loadLatestMessage(String chatroomId, String partnerId, String token) {
- Call> call = chatroomResource.getMessages(token, chatroomId, partnerId);
- call.enqueue(new Callback>() {
- @Override
- public void onResponse(Call> call, Response> response) {
- if (response.isSuccessful() && response.body() != null && !response.body().isEmpty()) {
- // 最新メッセージだけ反映
- latestMessage.setValue(response.body().get(response.body().size() - 1));
- }
- // else の場合は何もしない(UIにエラーを出さない)
- }
-
- @Override
- public void onFailure(Call> call, Throwable t) {
- // ネットワークエラー時もUIには表示しない
- Log.e("ChatViewModel", "loadLatestMessage error: " + t.getMessage());
- }
- });
- }
-
-
- // 4. チャットルーム削除 削除を実行した人の処理。削除された側の処理は含まれてません
- public void destroyChatroom(String chatroomId, String userId, String token) {
- Call call = chatroomResource.destroyChatroom(token, chatroomId, userId);
- call.enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) {
- // 成功でも失敗でも、画面を閉じる処理をUIに通知
- // 例えば LiveData を使って Activity/Fragment に伝える
- chatroomClosed.setValue(true);
-
- // ログには残す
- if (!response.isSuccessful()) {
- Log.e("ChatViewModel", "destroyChatroom failed: " + response.code());
- }
- }
-
- @Override
- public void onFailure(Call call, Throwable t) {
- // ネットワークエラーでも UI は閉じる
- chatroomClosed.setValue(true);
- Log.e("ChatViewModel", "destroyChatroom error: " + t.getMessage());
- }
- });
- }
-}
-
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/FriendReceivedRequestViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/FriendReceivedRequestViewModel.java
index 0b01c76..2fe45a8 100644
--- a/app/src/main/java/com/example/tampopo_client/viewmodels/FriendReceivedRequestViewModel.java
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/FriendReceivedRequestViewModel.java
@@ -17,58 +17,80 @@
import retrofit2.converter.scalars.ScalarsConverterFactory;
public class FriendReceivedRequestViewModel extends ViewModel {
- //サーバー(API)と通信するためのツール
+ // サーバー(API)と通信するためのツール
private final Retrofit retrofit;
- //APIの窓口
+ // API の窓口
private final FriendRequestsResource friendRequestsResource;
- //自分が受け取った申請
+ // 自分が受け取った申請
private final MutableLiveData> receivedRequests;
- //通信結果の状態
+ // 通信結果の状態
private final MutableLiveData operationResult;
- public FriendReceivedRequestViewModel() {
+ // 直近で使用したユーザーIDをキャッシュしておく
+ private String cachedUserId;
+ private String cachedToken;
+ public FriendReceivedRequestViewModel() {
this.retrofit = new Retrofit.Builder()
.baseUrl("http://nitta-lab-www.is.konan-u.ac.jp/tampopo/")
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.build();
+
this.friendRequestsResource = retrofit.create(FriendRequestsResource.class);
this.receivedRequests = new MutableLiveData<>(new ArrayList<>());
this.operationResult = new MutableLiveData<>();
}
- //viewがobserve出来るように
+ // viewがobserve出来るように
public MutableLiveData> getReceivedRequestsLiveData() {
return receivedRequests;
}
- //サーバーから受け取ったFriendReceivedRequestのデータを格納してキャッシュしていくぞ
- public void loadReceivedRequests(String token) {
- //tokenを渡して、受信フレンド申請一覧を取得するHTTPリクエスト(Webのサーバーに対して何かをお願いするメッセージ」)を作る準備をしている
+ public MutableLiveData getOperationResultLiveData() {
+ return operationResult;
+ }
+
+ // サーバーから受け取った FriendRequest のデータを読み込む
+ public void loadReceivedRequests(String token, String myUserId) {
+ // キャッシュ保存(削除後の再読み込み用)
+ this.cachedUserId = myUserId;
+ this.cachedToken = token;
+
Call> call = friendRequestsResource.getFriendRequests(token);
- //call.enqueueでサーバーへ送信(何を?)
call.enqueue(new Callback>() {
@Override
public void onResponse(Call> call, Response> response) {
if (response.isSuccessful()) {
- //通信が成功したらLiveDataへのキャッシュ
- receivedRequests.setValue(response.body());
- operationResult.setValue("Success");
- System.out.println("Success SetValue" + response.body());
+ List allRequests = response.body();
+ if (allRequests == null) allRequests = new ArrayList<>();
+
+ // ✅ 自分が受け取ったものだけを抽出
+ List receivedOnly = new ArrayList<>();
+ for (FriendRequest req : allRequests) {
+ if (req.getReceiverId() != null && req.getReceiverId().equals(myUserId)) {
+ receivedOnly.add(req);
+ }
+ }
+
+ receivedRequests.setValue(receivedOnly);
+ operationResult.setValue("Success (filtered " + receivedOnly.size() + " requests)");
+ System.out.println("Success SetValue (filtered): " + receivedOnly);
+
} else {
operationResult.setValue("Error: " + response.code());
- System.out.println("response error");
+ System.out.println("Response error: " + response.code());
}
}
@Override
public void onFailure(Call> call, Throwable t) {
operationResult.setValue("Network error: " + t.getMessage());
- System.out.println("ネットワークエラー: " + t);
+ System.out.println("Network error: " + t);
}
});
}
+
// フレンドリクエスト削除メソッド
public void deleteFriendRequest(String friendRequestId, String token) {
Call call = friendRequestsResource.deleteFriendRequest(friendRequestId, token);
@@ -78,8 +100,13 @@
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
operationResult.setValue("Friend request deleted successfully.");
- loadReceivedRequests(token); // 削除後、一覧を更新
System.out.println("Deleted friend request ID: " + friendRequestId);
+
+ // ✅ キャッシュがある場合は再読み込み
+ if (cachedToken != null && cachedUserId != null) {
+ loadReceivedRequests(cachedToken, cachedUserId);
+ }
+
} else {
operationResult.setValue("Error deleting request: " + response.code());
System.out.println("Error deleting request: " + response.code());
@@ -97,3 +124,4 @@
+
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/FriendViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/FriendViewModel.java
index 91b8021..6e958c5 100644
--- a/app/src/main/java/com/example/tampopo_client/viewmodels/FriendViewModel.java
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/FriendViewModel.java
@@ -45,7 +45,8 @@
}
public void loadFriends(String userId, String token){
- Call> call = usersResource.getFriends(userId, token);
+ //userResourceではなくfriendResourceに書き換え
+ Call> call = friendsResource.getFriends(userId, token);
call.enqueue(new Callback>() {
@Override
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/UserActivityStatusChangeListener.java b/app/src/main/java/com/example/tampopo_client/viewmodels/UserActivityStatusChangeListener.java
new file mode 100644
index 0000000..30724cc
--- /dev/null
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/UserActivityStatusChangeListener.java
@@ -0,0 +1,10 @@
+package com.example.tampopo_client.viewmodels;
+
+public interface UserActivityStatusChangeListener {
+ void onUserStatusChanged(String userId, Status activityStatus);
+
+ enum Status {
+ INACTIVE,
+ ACTIVE
+ }
+}
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/UserViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/UserViewModel.java
index e7c7920..4bd21e4 100644
--- a/app/src/main/java/com/example/tampopo_client/viewmodels/UserViewModel.java
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/UserViewModel.java
@@ -7,6 +7,8 @@
import com.example.tampopo_client.models.User;
import com.example.tampopo_client.resources.UserResource;
+import java.io.IOException;
+
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@@ -43,8 +45,10 @@
private static UserResource userResource;
private static final MutableLiveData user = new MutableLiveData<>();
private final MutableLiveData token = new MutableLiveData<>();
- private static final MutableLiveDataloading = new MutableLiveData<>(false);
- private static final MutableLiveData error = new MutableLiveData<>();
+ private final MutableLiveData icon = new MutableLiveData<>();
+ private final MutableLiveDataloading = new MutableLiveData<>(false);
+ private final MutableLiveData error = new MutableLiveData<>();
+
//コンストラクタ
public UserViewModel(){
@@ -58,6 +62,7 @@
public LiveData getUser() { return user; }
public LiveData getToken() { return token; }
+ public LiveData getIcon() { return icon; }
public LiveDataisLoading() { return loading;}
public static LiveData getError() { return error; }
@@ -103,6 +108,75 @@
}
});
}
+ //ニックネーム
+ public String getNickname(String id) {
+ Call call = userResource.getName(id);
+ try {
+ Response response = call.execute();
+
+ if (response.isSuccessful()) {
+ System.out.println(response.code());
+ return response.body();
+ } else {
+ System.out.println(response.code());
+ return null;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+//
+ }
+
+ //アイコン
+ public String getIcon(String id) {
+ Call call = userResource.getIcon(id);
+ try {
+ Response response = call.execute();
+
+ if (response.isSuccessful()) {
+ System.out.println(response.code());
+ return response.body();
+ } else {
+ System.out.println(response.code());
+ return null;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+// call.enqueue(new Callback() {
+// @Override
+// public void onResponse(Call call, Response response) {
+// if (response.isSuccessful()) {
+// icon.setValue(response.body());
+// System.out.println(response.code());
+// } else {
+// System.out.println(response.code());
+// }
+// }
+// @Override public void onFailure(Call call, Throwable t) {
+// System.out.println("エラー: " + t.getMessage());
+// }
+// });
+ }
+
+ public void updateIcon(String id, String newIcon, String token) {
+ Call call = userResource.updateIcon(id, newIcon, token);
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.isSuccessful()) {
+ icon.setValue(response.body());
+ System.out.println(response.code());
+
+ } else {
+ System.out.println(response.code());
+ }
+ }
+ @Override public void onFailure(Call call, Throwable t) {
+ System.out.println("エラー: " + t.getMessage());
+ }
+ });
+ }
//ニックネームの変更(市井)
public void updateName(String userId, String newName, String tokenValue) {
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 c88c250..3e43680 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
@@ -1,10 +1,13 @@
package com.example.tampopo_client.views;
+import android.content.Intent;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.ImageButton;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
@@ -13,19 +16,22 @@
import androidx.lifecycle.ViewModelProvider;
import com.example.tampopo_client.R;
import com.example.tampopo_client.Tampopo;
-import com.example.tampopo_client.viewmodels.ChatroomViewModel;
+import com.example.tampopo_client.viewmodels.ChatViewModel;
public class ChatActivity extends AppCompatActivity {
- private ChatroomViewModel chatroomViewModel;
+ private ChatViewModel chatroomViewModel;
//メンバー変数
private EditText senderMessage;
private EditText receiverMessage;
- private Button buttonSend;
+ private Button sendButton;
+ private Button backButton;
Tampopo tampopo;
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
tampopo = (Tampopo)getApplication();
@@ -34,11 +40,12 @@
EdgeToEdge.enable(this);//画面の端っこまで使う(Edge-to-Edge)表示
setContentView(R.layout.activity_chat);//表示する画面のレイアウトXMLファイル(activity_chat.xml)を指定
- chatroomViewModel = new ViewModelProvider(this).get(ChatroomViewModel.class);
+ chatroomViewModel = new ViewModelProvider(this).get(ChatViewModel.class);
senderMessage = findViewById(R.id.sender_message);
receiverMessage = findViewById(R.id.receiver_message);
- buttonSend = findViewById(R.id.buttonSend);
+ sendButton = findViewById(R.id.send_Button);
+ ImageButton backButton = findViewById(R.id.back_Button);
receiverMessage.setKeyListener(null);//受信メッセージ編集不可
@@ -56,32 +63,68 @@
// }
// });
-// String receiverText = senderMessage.getText().toString();//senderMessageにユーザーが入力した文字を取り出して、String型の 変数receiverText に入れる
-// if (!receiverText.isEmpty()) {
-// receiverMessage.setText(ChatroomViewModel.latestMessage);
-// }
+ Intent intent = getIntent();
+ String friendId = intent.getStringExtra("friendId");
+ String chatroomId = intent.getStringExtra("chatroomId");
- buttonSend.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- String senderText = senderMessage.getText().toString();//senderMessageにユーザーが入力した文字を取り出して、String型の 変数receiverText に入れる
- if (!senderText.isEmpty()) {
- String senderId = tampopo.getUserId();
- String token = tampopo.getToken();
- String chatroomId = tampopo.getChatroomId();
- chatroomViewModel.sendMessage(chatroomId, senderId, senderText, token);
- senderMessage.setText(senderText);//送信欄に表示
- }
- }
- });
+ Log.d("ChatDebug", "チャット相手ID: " + friendId);
+ Log.d("ChatDebug", "チャットルームID: " + chatroomId);
- chatroomViewModel.getLatestMessageLiveData().observe(this, receiverText -> {
- if (receiverText != null) {
- receiverMessage.setText(receiverText.getContent());
+ String myId = tampopo.getUserId();
+ String token = tampopo.getToken();
+ chatroomViewModel.enterChatroom(myId, friendId, token);
+
+ if (friendId == null || friendId.isEmpty()) {
+ Log.e("ChatDebug","Error: friendIdがnullです");
+ }
+
+ chatroomViewModel.getChatroomIdLiveData().observe(this, id -> {
+ if (id != null) {
+ tampopo.setChatroomId(id);
+ System.out.println("チャットルーム作成完了! ID: " + id);
+ } else {
+ System.out.println("チャットルーム作成に失敗しました");
}
});
+ //メッセージ送信
+ sendButton.setOnClickListener(new OnClickListener() { //sendButtonがクリックされたときの処理
+ @Override
+ public void onClick(View view) { //ボタンがクリックされたときに実行される処理本体
+ String senderText = senderMessage.getText().toString(); //senderMessageにユーザーが入力した文字を取り出して、String型の 変数receiverText に入れる
+ if (!senderText.isEmpty()) { //senderTextが空でなければ
+ String senderId = tampopo.getUserId();
+ String token = tampopo.getToken();
+ String chatroomId = tampopo.getChatroomId();
+ chatroomViewModel.sendMessage(chatroomId, senderId, senderText, token);
+ senderMessage.setText(senderText);//自分のメッセージを送信欄に表示
+ }
+ }
+ });
+
+
+ //メッセージ受信
+ chatroomViewModel.getLatestMessageLiveData().observe(this, chatMessage -> {
+ if (chatMessage != null) {
+ String myUserId = tampopo.getUserId(); // 自分のIDを取得
+ String senderId = chatMessage.getSenderId(); //相手(メッセージ送信者)のIDを取得
+
+ if (!myUserId.equals(senderId)) { //自分のIDが相手のIDと異なっていれば,(相手からのメッセージと判断)
+ receiverMessage.setText(chatMessage.getContent());// 相手からのメッセージを受信欄に表示
+ }
+ }
+ });
+
+
+ //戻るボタン
+ backButton.setOnClickListener(new OnClickListener() { //backButtonがクリックされたときの処理
+ public void onClick(View view) { //ボタンがクリックされたときに実行される処理本体
+ Intent intent = new Intent(ChatActivity.this, MainActivity.class); //ChatActivity から MainActivity に画面遷移
+ startActivity(intent);
+ }
+ });
+
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(Type.systemBars());
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 93b6087..696407e 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
@@ -1,73 +1,101 @@
package com.example.tampopo_client.views;
-import static androidx.core.content.ContextCompat.startActivity;
-
+import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.text.TextPaint;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.Button;
import android.widget.FrameLayout;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.Toast;
-import androidx.activity.EdgeToEdge;
import androidx.lifecycle.Observer;
import com.bumptech.glide.Glide;
import com.example.tampopo_client.R;
+import com.example.tampopo_client.Tampopo;
import com.example.tampopo_client.models.Activity;
-import com.example.tampopo_client.viewmodels.ActivityViewModel;
+import com.example.tampopo_client.viewmodels.ChatViewModel;
import com.google.android.material.imageview.ShapeableImageView;
import java.util.List;
-import java.util.Map;
-/**
- * TODO: document your custom view class.
- */
-public class FriendIconView extends FrameLayout implements Observer>{
- private String mExampleString; // TODO: use a default from R.string...
-// private int mExampleColor = Color.RED; // TODO: use a default from R.color...
- private float mExampleDimension = 0; // TODO: use a default from R.dimen...
- private Drawable mExampleDrawable;
-
- private TextPaint mTextPaint;
- private float mTextWidth;
- private float mTextHeight;
+public class FriendIconView extends FrameLayout {
private ShapeableImageView mFriendIcon;
private ImageView mFriendCommentImage;
private TextView mFriendComment;
private TextView mFriendNickname;
private ImageView mFriendChatNotification;
private boolean chatNotification = false;
- private Observer> activityObserver;
- String friendActivity = "123";
+ private String friendActivity;
+ private String friendUserId;
+ 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());
+ }
+ }
+ };
+
+ //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 Observer> getActivitiesObserver() {
+ return activitiesObserver;
+ }
+
+ public Observer getChatObserver() {
+ return chatObserver;
+ }
+
+ public FriendIconView(Context context, String friendUserId, ChatViewModel chatViewModel) {
+ this(context);
+ this.friendUserId = friendUserId;
+ this.chatViewModel = chatViewModel;
+ init(null, 0);
+ }
+
public FriendIconView(Context context) {
super(context);
+ this.friendUserId = null;
init(null, 0);
}
public FriendIconView(Context context, AttributeSet attrs) {
super(context, attrs);
+ this.friendUserId = null;
init(attrs, 0);
}
public FriendIconView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ this.friendUserId = null;
init(attrs, defStyle);
}
private void init(AttributeSet attrs, int defStyle) {
- LayoutInflater.from(getContext()).inflate(R.layout.sample_friend_icon_view,this,true);
+ LayoutInflater.from(getContext()).inflate(R.layout.sample_friend_icon_view, this, true);
mFriendCommentImage = findViewById(R.id.friend_comment_image);
mFriendComment = findViewById(R.id.friend_comment);
mFriendNickname = findViewById(R.id.friend_nickname);
@@ -75,64 +103,64 @@
mFriendChatNotification = findViewById(R.id.chat_notification);
//true(チャット通知が来た時)なら表示
- if(chatNotification){
+ if (chatNotification) {
mFriendChatNotification.setVisibility(View.VISIBLE);
}
//false(チャット通知が来ていない)なら非表示
- else{
+ else {
mFriendChatNotification.setVisibility(View.GONE);
}
//iconを押したらチャットを始めることができる(チャットのダイアログができたらFriendActivityを変更)
mFriendIcon.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
- Context ctx = getContext();
- Intent intent = new Intent(ctx, ChatActivity. class);
- ctx.startActivity(intent);
+ 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);
+ }
}
});
-// if(attrs != null){
-// TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FriendIconView, defStyle, 0);
-// String nickname = a.getString(R.styleable.FriendIconView_nickname);
-// if(nickname != null){
-// setNickname(nickname);
-// }
-// Drawable iconDrawable = a.getDrawable(R.styleable.FriendIconView_iconSrc);
-// if(iconDrawable != null){
-// mFriendIcon.setImageDrawable(iconDrawable);
-// }
-// a.recycle();
-// }
+ }
- // Load attributes
-// final TypedArray a = getContext().obtainStyledAttributes(
-// attrs, R.styleable.FriendIconView, defStyle, 0);
-//
-// mExampleString = a.getString(
-// R.styleable.FriendIconView_exampleString);
-// mExampleColor = a.getColor(
-// R.styleable.FriendIconView_exampleColor,
-// mExampleColor);
-// // Use getDimensionPixelSize or getDimensionPixelOffset when dealing with
-// // values that should fall on pixel boundaries.
-// mExampleDimension = a.getDimension(
-// R.styleable.FriendIconView_exampleDimension,
-// mExampleDimension);
-//
-// if (a.hasValue(R.styleable.FriendIconView_exampleDrawable)) {
-// mExampleDrawable = a.getDrawable(
-// R.styleable.FriendIconView_exampleDrawable);
-// mExampleDrawable.setCallback(this);
-// }
+ 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);
-// // Set up a default TextPaint object
-// mTextPaint = new TextPaint();
-// mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
-// mTextPaint.setTextAlign(Paint.Align.LEFT);
-//
-// // Update TextPaint and text measurements from attributes
-// invalidateTextPaintAndMeasurements();
-//
+ // メッセージテキスト
+ TextView tvMessage = dialog.findViewById(R.id.tv_message);
+ tvMessage.setText(fromUserName + " さんと通話を開始しますか?");
+
+ // 開始ボタン
+ Button btnStart = dialog.findViewById(R.id.btn_start);
+ btnStart.setOnClickListener(v -> {
+ Toast.makeText(context, "通話を開始しました", Toast.LENGTH_SHORT).show();
+ dialog.dismiss();
+
+ // 通話を開始する
+ Tampopo tampopo = (Tampopo) ((MainActivity) getContext()).getApplication();
+// String chatroomId = chatViewModel.enterChatroom(tampopo.getUserId(), friendUserId, tampopo.getToken());
+
+ // 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());
+
+ dialog.show();
}
public void setNickname(String nickname) {
@@ -147,11 +175,12 @@
}
}
- public ImageView getImageView(){
+ public ImageView getImageView() {
return mFriendIcon;
}
- public void setComment(String comment){
- if(mFriendComment != null){
+
+ public void setComment(String comment) {
+ if (mFriendComment != null) {
int comment_length = comment.length();
if (comment_length > 20) {
mFriendComment.setTextSize(7);
@@ -166,156 +195,46 @@
// public void setActivityLiveDataObserver(String uid, ActivityViewModel viewModel){
// activityObserver = new Observer>() {
- @Override
- public void onChanged(List activityList) {
- if(activityList != null && !activityList.isEmpty()){
- Activity act = activityList.get(0);
- friendActivity = act.getText();
- setAccount(act.getUserId());
- }
- }
+
+ // 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);
// }
- //uidを引数にカスタムビューにニックネーム,コメント,アイコンをセットする
- public void setAccount(String uid){
- setNickname("haru");
- setComment((friendActivity));
- String imageUrl = "http://nitta-lab-www.is.konan-u.ac.jp/tampopo-data/icon" + uid + ".jpg";
- Glide.with(getContext())
- .load(imageUrl)
- .into(getImageView());
+ /**
+ * FriendIconViewのアイコン画像を更新する
+ *
+ * @param iconUrl アイコン画像のURL
+ */
+ public void setIconUrl(String iconUrl) {
+ Glide.with(getContext()).load(iconUrl).into(getImageView());
}
- public void setChatNotification(boolean chat){
+
+ //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){
+ if (chat) {
mFriendChatNotification.setVisibility(View.VISIBLE);
}
//false(チャット通知が来ていない)なら非表示
- else{
+ else {
mFriendChatNotification.setVisibility(View.GONE);
}
}
-// private void invalidateTextPaintAndMeasurements() {
-// mTextPaint.setTextSize(mExampleDimension);
-// mTextPaint.setColor(mExampleColor);
-// mTextWidth = mTextPaint.measureText(mExampleString);
-//
-// Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
-// mTextHeight = fontMetrics.bottom;
-// }
-
-// @Override
-// protected void onDraw(Canvas canvas) {
-// super.onDraw(canvas);
-//
-// // TODO: consider storing these as member variables to reduce
-// // allocations per draw cycle.
-// int paddingLeft = getPaddingLeft();
-// int paddingTop = getPaddingTop();
-// int paddingRight = getPaddingRight();
-// int paddingBottom = getPaddingBottom();
-//
-// int contentWidth = getWidth() - paddingLeft - paddingRight;
-// int contentHeight = getHeight() - paddingTop - paddingBottom;
-//
-// // Draw the text.
-// canvas.drawText(mExampleString,
-// paddingLeft + (contentWidth - mTextWidth) / 2,
-// paddingTop + (contentHeight + mTextHeight) / 2,
-// mTextPaint);
-//
-// // Draw the example drawable on top of the text.
-// if (mExampleDrawable != null) {
-// mExampleDrawable.setBounds(paddingLeft, paddingTop,
-// paddingLeft + contentWidth, paddingTop + contentHeight);
-// mExampleDrawable.draw(canvas);
-// }
-// }
-
- /**
- * Gets the example string attribute value.
- *
- * @return The example string attribute value.
- */
- public String getExampleString() {
- return mExampleString;
- }
-
- /**
- * Sets the view"s example string attribute value. In the example view, this string
- * is the text to draw.
- *
- * @param exampleString The example string attribute value to use.
- */
-// public void setExampleString(String exampleString) {
-// mExampleString = exampleString;
-// invalidateTextPaintAndMeasurements();
-// }
-
- /**
- * Gets the example color attribute value.
- *
- * @return The example color attribute value.
- */
-// public int getExampleColor() {
-// return mExampleColor;
-// }
-
- /**
- * Sets the view"s example color attribute value. In the example view, this color
- * is the font color.
- *
- * @param exampleColor The example color attribute value to use.
- */
-// public void setExampleColor(int exampleColor) {
-// mExampleColor = exampleColor;
-// invalidateTextPaintAndMeasurements();
-// }
-
- /**
- * Gets the example dimension attribute value.
- *
- * @return The example dimension attribute value.
- */
- public float getExampleDimension() {
- return mExampleDimension;
- }
-
- /**
- * Sets the view"s example dimension attribute value. In the example view, this dimension
- * is the font size.
- *
- * @param exampleDimension The example dimension attribute value to use.
- */
-// public void setExampleDimension(float exampleDimension) {
-// mExampleDimension = exampleDimension;
-// invalidateTextPaintAndMeasurements();
-// }
-
- /**
- * Gets the example drawable attribute value.
- *
- * @return The example drawable attribute value.
- */
- public Drawable getExampleDrawable() {
- return mExampleDrawable;
- }
-
- /**
- * Sets the view"s example drawable attribute value. In the example view, this drawable is
- * drawn above the text.
- *
- * @param exampleDrawable The example drawable attribute value to use.
- */
- public void setExampleDrawable(Drawable exampleDrawable) {
- mExampleDrawable = exampleDrawable;
- }
-
-// @Override
-// public void onChanged(List activityList) {
-// activityList.get(0).
-// }
}
diff --git a/app/src/main/java/com/example/tampopo_client/views/FriendListFragment.java b/app/src/main/java/com/example/tampopo_client/views/FriendListFragment.java
index 722c7b7..17730c5 100644
--- a/app/src/main/java/com/example/tampopo_client/views/FriendListFragment.java
+++ b/app/src/main/java/com/example/tampopo_client/views/FriendListFragment.java
@@ -31,6 +31,8 @@
// TODO: Customize parameters
private int mColumnCount = 1;
+ private MyFriendRecyclerViewAdapter adapter;
+
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
@@ -39,7 +41,15 @@
}
// TODO: Customize parameter initialization
- @SuppressWarnings("unused")
+// @SuppressWarnings("unused")
+// public static FriendListFragment newInstance(int columnCount) {
+// FriendListFragment fragment = new FriendListFragment();
+// Bundle args = new Bundle();
+// args.putInt(ARG_COLUMN_COUNT, columnCount);
+// fragment.setArguments(args);
+// return fragment;
+// }
+
public static FriendListFragment newInstance(int columnCount) {
FriendListFragment fragment = new FriendListFragment();
Bundle args = new Bundle();
@@ -57,48 +67,113 @@
}
}
+// @Override
+// public View onCreateView(LayoutInflater inflater, ViewGroup container,
+// Bundle savedInstanceState) {
+// View view = inflater.inflate(R.layout.fragment_friend_list_list, container, false);
+//
+// RecyclerView recyclerView = view.findViewById(R.id.list);
+// Context context = view.getContext();
+//
+// // Add some sample items.
+// //for (int i = 1; i <= 30; i++) {
+// // FriendContent.addItem(new FriendContent.FriendItem(Integer.toString(i), "ユーザ" + i));
+// //}
+//
+// // Set the adapter
+// if (view instanceof RecyclerView) {
+// Context context = view.getContext();
+// RecyclerView recyclerView = (RecyclerView) view;
+// if (mColumnCount <= 1) {
+// recyclerView.setLayoutManager(new LinearLayoutManager(context));
+// } else {
+// recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
+// }
+// recyclerView.setAdapter(new MyFriendRecyclerViewAdapter(FriendContent.ITEMS));
+// }
+// adapter = new MyFriendRecyclerViewAdapter(FriendContent.ITEMS);
+// recyclerView.setAdapter(adapter);
+// return view;
+// }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_friend_list_list, container, false);
- // Add some sample items.
- //for (int i = 1; i <= 30; i++) {
- // FriendContent.addItem(new FriendContent.FriendItem(Integer.toString(i), "ユーザ" + i));
- //}
+ RecyclerView recyclerView = view.findViewById(R.id.list);
+ Context context = view.getContext();
- // Set the adapter
- if (view instanceof RecyclerView) {
- Context context = view.getContext();
- RecyclerView recyclerView = (RecyclerView) view;
- if (mColumnCount <= 1) {
- recyclerView.setLayoutManager(new LinearLayoutManager(context));
- } else {
- recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
- }
- recyclerView.setAdapter(new MyFriendRecyclerViewAdapter(FriendContent.ITEMS));
+ if (mColumnCount <= 1) {
+ recyclerView.setLayoutManager(new LinearLayoutManager(context));
+ } else {
+ recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
}
+
+ // adapterをここで初期化
+ adapter = new MyFriendRecyclerViewAdapter(FriendContent.ITEMS);
+ recyclerView.setAdapter(adapter);
+
return view;
}
+
+// @Override
+// public void onViewCreated(View view, Bundle savedInstanceState) {
+// super.onViewCreated(view, savedInstanceState);
+// FriendViewModel friendViewModel = new ViewModelProvider(this).get(FriendViewModel.class);
+//
+// String userId = ((Tampopo) ((FriendActivity) view.getContext()).getApplication()).getUserId;
+// String token = ((Tampopo) ((FriendActivity) view.getContext()).getApplication()).getToken;
+// friendViewModel.loadFriends(userId, token);
+//
+// friendViewModel.getFriendIdsLiveData().observe(getViewLifecycleOwner(), new Observer>() {
+//
+// @Override
+// public void onChanged(List friendIds) {
+// for (String i : friendIds) {
+// FriendContent.addItem(new FriendContent.FriendItem(i, ""));
+// }
+// adapter.notifyDataSetChanged();
+// }
+// });
+// }
+
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FriendViewModel friendViewModel = new ViewModelProvider(this).get(FriendViewModel.class);
- String userId = ((Tampopo) ((FriendActivity) view.getContext()).getApplication()).getUserId();
- String token = ((Tampopo) ((FriendActivity) view.getContext()).getApplication()).getToken();
+//自分の情報を取得する
+ Tampopo app = (Tampopo) requireActivity().getApplication();
+ String userId = app.getUserId();
+ String token = app.getToken();
+
+//サーバーからフレンド一覧を取得する
friendViewModel.loadFriends(userId, token);
- friendViewModel.getFriendIdsLiveData().observe(getViewLifecycleOwner(), new Observer>() {
-
- @Override
- public void onChanged(List friendIds) {
- for (String i : friendIds) {
- FriendContent.addItem(new FriendContent.FriendItem(i, ""));
+//一旦旧コードをコメントアウトしました。
+// friendViewModel.getFriendIdsLiveData().observe(getViewLifecycleOwner(), new Observer>() {
+// @Override
+// public void onChanged(List friendIds) {
+// // 一度リセットして新しいリストを追加
+// FriendContent.clear();
+// for (String id : friendIds) {
+// FriendContent.addItem(new FriendContent.FriendItem(id, ""));
+// }
+// // adapterがクラス変数なのでここで使える
+// adapter.notifyDataSetChanged();
+// }
+// });
+ friendViewModel.getFriendIdsLiveData().observe(getViewLifecycleOwner(), friendIds -> {
+ FriendContent.clear();
+ if (friendIds != null) {
+ for (String id : friendIds) {
+ FriendContent.addItem(new FriendContent.FriendItem(id, ""));
}
}
+ adapter.notifyDataSetChanged();
});
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tampopo_client/views/FriendReceivedFragment.java b/app/src/main/java/com/example/tampopo_client/views/FriendReceivedFragment.java
index 20e07a1..ddfc0bd 100644
--- a/app/src/main/java/com/example/tampopo_client/views/FriendReceivedFragment.java
+++ b/app/src/main/java/com/example/tampopo_client/views/FriendReceivedFragment.java
@@ -108,7 +108,8 @@
// 受信した友達申請を管理する ViewModel を取得
FriendReceivedRequestViewModel friendReceivedRequestViewModel = new ViewModelProvider(this).get(FriendReceivedRequestViewModel.class);
// サーバーから受信した友達リクエスト一覧をロード
- friendReceivedRequestViewModel.loadReceivedRequests(tampopo.getToken());
+ //tampopo.getUserIdを追加しました
+ friendReceivedRequestViewModel.loadReceivedRequests(tampopo.getToken(),tampopo.getUserId());
// LiveData を監視して、データが変わったら RecyclerView に反映
friendReceivedRequestViewModel.getReceivedRequestsLiveData().observe(getViewLifecycleOwner(), new Observer>() {
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 29af578..f2fa84a 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
@@ -39,6 +39,8 @@
import com.example.tampopo_client.Tampopo;
import com.example.tampopo_client.models.Activity;
import com.example.tampopo_client.viewmodels.ActivityViewModel;
+import com.example.tampopo_client.viewmodels.ChatViewModelFactory;
+import com.example.tampopo_client.viewmodels.UserViewModel;
import com.google.android.material.imageview.ShapeableImageView;
import com.example.tampopo_client.viewmodels.ActivityViewModelFactory;
import com.example.tampopo_client.viewmodels.ChatViewModel;
@@ -62,9 +64,13 @@
private Map userViews = new HashMap<>();
ActivityViewModel activityViewModel;
+ UserViewModel userViewModel;
Tampopo tampopo;
+ //追加しました!
private ChatViewModel chatViewModel;
+ private final List recentUpdatedFriends = new ArrayList<>(); // 最新6人
+
@Override
@@ -92,6 +98,10 @@
}
}
+ // TODO: CHANGE
+ userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
+
+
// handleIncomingIntent(getIntent());
//メイン画面からフレンド一覧画面への遷移
ImageButton friendButton = (ImageButton) findViewById(R.id.friend);
@@ -109,9 +119,10 @@
ActivityViewModelFactory factory = new ActivityViewModelFactory(tampopo.getUserId(), tampopo.getToken()); // Factoryを使って、引数をコンストラクタにわたしつつViewModelを作成
activityViewModel = new ViewModelProvider(this, factory).get(ActivityViewModel.class);
+ //追加しました!!!!!!!!!!!
// ChatViewModelを初期化する
- chatViewModel = new ViewModelProvider(this).get(ChatViewModel.class);
-
+ 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>() {
@@ -125,6 +136,7 @@
// });
MutableLiveData> friendsLiveData = activityViewModel.getFriendUserIdsLiveData();
+
friendsLiveData.observe(this, new Observer>() {
@Override
public void onChanged(List friends) {
@@ -134,14 +146,59 @@
});
for (String friendId: userViews.keySet()) {
- MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(friendId);
- activitiesLiveData.observe(this, new Observer>() {
+ 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");
+// }
+ });
+ }).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));
+ //activitiesLiveData.observe(this, userViews.get(friendId));
}
//メイン画面から通知一覧画面への遷移
@@ -307,6 +364,8 @@
// Activity activity = entry;
FriendIconView userView = userViews.get(friendId);
+ MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(friendId);
+
if (userView == null) {
// 新しいユーザなので、アイコン+コメントを作成
@@ -342,6 +401,9 @@
userViews.put(friendId, container);
messageList.addView(container);
+ // TODO: CHANGE
+ activitiesLiveData.observeForever(container.getActivitiesObserver());
+
// } else {
// // 既に表示されている → コメントだけ更新
// TextView commentView = (TextView) ((LinearLayout) userView).getChildAt(1);
@@ -510,13 +572,14 @@
dialog.show();
}
-
+//通知を受信したときのダイアログ これが動いてます
+ //friendName+から通話があります。ってでるから通知が来たときのフレンドを変数に置く必要がある
@Override
public void onNotificationReceived() {
// 通知を受信したときにダイアログを表示
- runOnUiThread(() -> showChatNotification("user01"));
+ runOnUiThread(() -> showChatNotification("user02"));
// アイコンを赤枠に
- runOnUiThread(() -> highlightUserIcon("user01"));
+ //runOnUiThread(() -> highlightUserIcon("user01"));
}
// @Override
// protected void onNewIntent(Intent intent) {
diff --git a/app/src/main/java/com/example/tampopo_client/views/MyFragmentAdapter.java b/app/src/main/java/com/example/tampopo_client/views/MyFragmentAdapter.java
index 5786821..bdde5e5 100644
--- a/app/src/main/java/com/example/tampopo_client/views/MyFragmentAdapter.java
+++ b/app/src/main/java/com/example/tampopo_client/views/MyFragmentAdapter.java
@@ -28,3 +28,4 @@
return 2;
}
}
+
diff --git a/app/src/main/java/com/example/tampopo_client/views/MyFriendRecyclerViewAdapter.java b/app/src/main/java/com/example/tampopo_client/views/MyFriendRecyclerViewAdapter.java
index 22ef86b..e2a231d 100644
--- a/app/src/main/java/com/example/tampopo_client/views/MyFriendRecyclerViewAdapter.java
+++ b/app/src/main/java/com/example/tampopo_client/views/MyFriendRecyclerViewAdapter.java
@@ -1,40 +1,105 @@
+//旧コードは念の為コメントアウトしています。
+//package com.example.tampopo_client.views;
+//
+//import android.view.LayoutInflater;
+//import android.view.ViewGroup;
+//import android.widget.TextView;
+//
+//import com.example.tampopo_client.databinding.FragmentFriendListBinding;
+//import com.example.tampopo_client.views.placeholder.FriendContent;
+//
+//import java.util.List;
+//
+//import androidx.recyclerview.widget.RecyclerView;
+//
+///**
+// * {@link RecyclerView.Adapter} that can display a {@link FriendContent.FriendItem}.
+// * TODO: Replace the implementation with code for your data type.
+// */
+//public class MyFriendRecyclerViewAdapter extends RecyclerView.Adapter {
+//
+// private final List mValues;
+//
+// public MyFriendRecyclerViewAdapter(List items) {
+// mValues = items;
+// }
+//
+// @Override
+// public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+//
+// return new ViewHolder(FragmentFriendListBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
+//
+// }
+//
+// @Override
+// public void onBindViewHolder(final ViewHolder holder, int position) {
+// holder.mItem = mValues.get(position);
+// //holder.mIdView.setText(mValues.get(position).id);
+// holder.mContentView.setText(mValues.get(position).name);
+// }
+//
+// @Override
+// public int getItemCount() {
+// return mValues.size();
+// }
+//
+// public class ViewHolder extends RecyclerView.ViewHolder {
+// //public final TextView mIdView;
+// public final TextView mContentView;
+// public FriendContent.FriendItem mItem;
+//
+// public ViewHolder(FragmentFriendListBinding binding) {
+// super(binding.getRoot());
+// //mIdView = binding.itemNumber;
+// mContentView = binding.content;
+// }
+//
+// @Override
+// public String toString() {
+// return super.toString() + " '" + mContentView.getText() + "'";
+// }
+// }
+//}
+
package com.example.tampopo_client.views;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.TextView;
-import com.example.tampopo_client.databinding.FragmentFriendListBinding;
-import com.example.tampopo_client.views.placeholder.FriendContent;
-
-import java.util.List;
-
import androidx.recyclerview.widget.RecyclerView;
-/**
- * {@link RecyclerView.Adapter} that can display a {@link FriendContent.FriendItem}.
- * TODO: Replace the implementation with code for your data type.
- */
+import com.example.tampopo_client.R;
+import com.example.tampopo_client.views.placeholder.FriendContent.FriendItem;
+
+import java.util.List;
+
public class MyFriendRecyclerViewAdapter extends RecyclerView.Adapter {
- private final List mValues;
+ private final List mValues;
- public MyFriendRecyclerViewAdapter(List items) {
+ public MyFriendRecyclerViewAdapter(List items) {
mValues = items;
}
+ //各行のビューを作成する
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-
- return new ViewHolder(FragmentFriendListBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
-
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.fragment_friend_list, parent, false);
+ return new ViewHolder(view);
}
+
+ //データをビューに紐付ける
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
- holder.mItem = mValues.get(position);
- //holder.mIdView.setText(mValues.get(position).id);
- holder.mContentView.setText(mValues.get(position).name);
+ FriendItem item = mValues.get(position);
+ holder.userIdView.setText(item.id);
+ holder.contentView.setText(item.name);
+ holder.userIcon.setImageResource(R.drawable.friend);
}
@Override
@@ -43,19 +108,15 @@
}
public class ViewHolder extends RecyclerView.ViewHolder {
- //public final TextView mIdView;
- public final TextView mContentView;
- public FriendContent.FriendItem mItem;
+ public final ImageView userIcon;
+ public final TextView contentView;
+ public final TextView userIdView;
- public ViewHolder(FragmentFriendListBinding binding) {
- super(binding.getRoot());
- //mIdView = binding.itemNumber;
- mContentView = binding.content;
- }
-
- @Override
- public String toString() {
- return super.toString() + " '" + mContentView.getText() + "'";
+ public ViewHolder(View view) {
+ super(view);
+ userIcon = view.findViewById(R.id.usericon);
+ contentView = view.findViewById(R.id.content);
+ userIdView = view.findViewById(R.id.userId);
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/example/tampopo_client/views/TestFriendIconActivity.java b/app/src/main/java/com/example/tampopo_client/views/TestFriendIconActivity.java
index b70cc11..06c2cc3 100644
--- a/app/src/main/java/com/example/tampopo_client/views/TestFriendIconActivity.java
+++ b/app/src/main/java/com/example/tampopo_client/views/TestFriendIconActivity.java
@@ -33,26 +33,28 @@
float density = getResources().getDisplayMetrics().density;
//FriendIconView 1個目
+ String uid = "haru";
FriendIconView view1 = new FriendIconView(this);
+ //view1.setAccount(uid);
FrameLayout.LayoutParams params1 = new FrameLayout.LayoutParams(
- (int) (160*density), // width in px
- (int) (100*density) // height in px
+ (int) (250*density), // width in px
+ (int) (250*density) // height in px
);
view1.setLayoutParams(params1);
- view1.setX(100); // px単位
+ view1.setX(130); // px単位
view1.setY(150);
rootLayout.addView(view1);
//FriendIconView 2個目
FriendIconView view2 = new FriendIconView(this);
FrameLayout.LayoutParams params2 = new FrameLayout.LayoutParams(
- (int) (160*density),
- (int) (100*density)
+ (int) (250*density),
+ (int) (250*density)
);
- view1.setLayoutParams(params2);
- view1.setX(100);
- view1.setY(150);
- rootLayout.addView(view1);
+ view2.setLayoutParams(params2);
+ view2.setX(200);
+ view2.setY(600);
+ rootLayout.addView(view2);
setContentView(rootLayout);
//
diff --git a/app/src/main/java/com/example/tampopo_client/views/placeholder/FriendContent.java b/app/src/main/java/com/example/tampopo_client/views/placeholder/FriendContent.java
index 3c48f8e..f399d6f 100644
--- a/app/src/main/java/com/example/tampopo_client/views/placeholder/FriendContent.java
+++ b/app/src/main/java/com/example/tampopo_client/views/placeholder/FriendContent.java
@@ -40,6 +40,11 @@
ITEM_MAP.put(item.id, item);
}
+ public static void clear() {
+ ITEMS.clear();
+ ITEM_MAP.clear();
+ }
+
//private static FriendItem createPlaceholderItem(int position) {
// return new FriendItem(String.valueOf(position), "ユーザー名 " , makeDetails(position));
diff --git a/app/src/main/res/layout/activity_chat.xml b/app/src/main/res/layout/activity_chat.xml
index ec31135..9a43176 100644
--- a/app/src/main/res/layout/activity_chat.xml
+++ b/app/src/main/res/layout/activity_chat.xml
@@ -41,7 +41,7 @@
app:layout_constraintVertical_bias="0.55" />
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ android:layout_marginStart="5dp"
+ android:layout_marginTop="5dp" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_launch.xml b/app/src/main/res/layout/activity_launch.xml
index cc3237c..0bbb192 100644
--- a/app/src/main/res/layout/activity_launch.xml
+++ b/app/src/main/res/layout/activity_launch.xml
@@ -6,7 +6,8 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".views.LaunchActivity">
+ tools:context=".views.LaunchActivity"
+ android:background="#E0F7FA">
+ tools:context=".views.RegisterActivity"
+ android:background="#E0F7FA">
-
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file