diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index b268ef3..4c3d0eb 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,6 +4,14 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..2e7eabd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,7 @@ + - + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file 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 455723a..86f5863 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 @@ -7,7 +7,7 @@ import com.example.tampopo_client.models.Activity; import com.example.tampopo_client.resources.ActivitiesResource; -import com.example.tampopo_client.resources.UserResource; +import com.example.tampopo_client.resources.FriendsResource; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -34,7 +34,15 @@ */ public class ActivityViewModel extends RealTimeViewModel { private final ActivitiesResource activitiesResource; - private final UserResource userResource; + /** + * フレンド一覧取得用のリソース。 + * + * Swagger ではフレンドのユーザーID一覧は + * GET /friends/users/{user-id} + * で配列として返される仕様になっているため、 + * こちらの FriendsResource を利用する。 + */ + private final FriendsResource friendsResource; private final MutableLiveData myLatestActivityLiveData; // 自分の最新のアクティビティ private final Map>> friendToActivitiesLiveData; // <フレンドのユーザーID, フレンドのアクティビティのリスト> @@ -61,7 +69,7 @@ // 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); + friendsResource = retrofit.create(FriendsResource.class); friendToActivitiesLiveData = new HashMap<>(); friendUserIdsLiveData = new MutableLiveData<>(List.of()); @@ -109,8 +117,9 @@ }); // 自分のフレンドの最新のアクティビティを取得して更新する - if (friendUserIdsLiveData.isInitialized() && friendUserIdsLiveData.getValue() != null) { - for (String userId : friendUserIdsLiveData.getValue()) { + List currentFriendIds = friendUserIdsLiveData.getValue(); + if (currentFriendIds != null && !currentFriendIds.isEmpty()) { + for (String userId : currentFriendIds) { pullLatestActivity(userId, activitiesResource, new ActivityFetchCallback() { @Override public void onSuccess(Activity activity) { @@ -125,11 +134,10 @@ } } - if (friendUserIdsLiveData.isInitialized()) { - // 最新のフレンドのユーザーIDを取得して更新する - // TODO: 適切なコールバックを使う必要あり - pullLatestFriendUserIds(myUserId, myToken); - } + // 最新のフレンドのユーザーIDを取得して更新する + // LiveData の初期化状態に依存せず、常にサーバから最新のフレンド一覧を取得する + // TODO: 適切なコールバックを使う必要あり + pullLatestFriendUserIds(myUserId, myToken); }; } @@ -145,18 +153,19 @@ } MutableLiveData> userActivitiesLiveData = friendToActivitiesLiveData.get(userId); assert userActivitiesLiveData != null; + // + // NOTE: + // 以前は「同じ activityId の場合は更新しない」という条件になっていたが、 + // サーバ側の実装によっては、同じ activityId のまま text だけ書き換えられるケースがある。 + // その場合、LiveData が更新されず、Observer(FriendIconView の吹き出し)が + // 一切反応しない問題が発生していた。 + // + // フレンドの最新アクティビティは 1 件だけ保持していれば十分なので、 + // activityId に関わらず常に最新の値で上書きするようにしている。 + // これにより、同一 ID で内容だけ変わる更新でも必ず UI に反映される。 + // - List userActivities = userActivitiesLiveData.getValue(); - - if (userActivities == null || userActivities.isEmpty()) { - userActivitiesLiveData.postValue(List.of(latestActivity)); - } else { - if (userActivities.get(0).getActivityId().equals(latestActivity.getActivityId())) { - return; - } - - userActivitiesLiveData.postValue(List.of(latestActivity)); - } + userActivitiesLiveData.postValue(List.of(latestActivity)); } /** @@ -167,10 +176,6 @@ * @param newActivity 新しいアクティビティのテキスト */ public void createActivity(String userId, String token, String newActivity) { - if (!myLatestActivityLiveData.isInitialized()) { - return; - } - Call createActivityCall = activitiesResource.addActivity(userId, token, newActivity); createActivityCall.enqueue(new Callback() { @Override @@ -256,34 +261,54 @@ * @param token 自分のユーザー認証用トークン */ private void pullLatestFriendUserIds(String userId, String token) { - Call> fetchFriendUserIdsCall = userResource.getFriends(userId, token); + // NOTE: + // 以前は UserResource#getFriends("/users/{user-id}/friends") を利用していたが、 + // Swagger 上ではこのエンドポイントは「ペアID → ユーザーID」のマップを返す仕様になっており、 + // List として扱うには不整合があった。 + // + // 一方で、 + // GET /friends/users/{user-id} + // はフレンドのユーザーID一覧をそのまま配列で返すエンドポイントとして定義されている。 + // こちらを FriendsResource 経由で呼び出すことで、 + // friendUserIdsLiveData に正しいフレンドID一覧が格納されるようにする。 + Call> fetchFriendUserIdsCall = friendsResource.getFriends(userId, token); fetchFriendUserIdsCall.enqueue(new Callback>() { @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { if (response.isSuccessful()) { + // 取得したフレンドID一覧 + List newFriendUserIds = 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())); + // LiveData に設定済みの値と同じであれば何もしない + List currentFriendUserIds = friendUserIdsLiveData.getValue(); + if (currentFriendUserIds != null && currentFriendUserIds.equals(newFriendUserIds)) { + return; } + + // LiveData を最新のフレンド一覧で更新 + friendUserIdsLiveData.postValue(newFriendUserIds); + + // 以下は「最近アクティビティを更新した順」にフレンドIDを並べ替える処理 + if (newFriendUserIds == null || newFriendUserIds.isEmpty()) { + sortedFriendUserIds.clear(); + return; + } + + SortedSet friends = new TreeSet<>(new Friend.UpdateTimeComparator()); + + newFriendUserIds.forEach(id -> { + List activities = getActivitiesLiveDataFromUserId(id).getValue(); + if (activities == null || activities.isEmpty()) { + return; + } + + Activity latestActivity = activities.get(0); + friends.add(new Friend(id, latestActivity.getUpdateTime())); + }); + + // 並び替えたフレンドのユーザーIDを順番に格納して更新する + sortedFriendUserIds.clear(); + friends.forEach(friend -> sortedFriendUserIds.add(friend.getUserId())); } } 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 9911876..7f5b854 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 @@ -130,45 +130,8 @@ } }); - //アクティビティを投稿した人がアクティビティを更新しないか監視する - //なにかをクリックしたらここに飛んでくる - for (String friendId : userViews.keySet()) { - //final String updateFriendId = friendId; - MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(friendId); - //MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId); - - //FriendIconView friendView = userViews.get(friendId); - //if (friendView == null) continue; - - activitiesLiveData.observeForever(new Observer>() { - //アクティビティを更新したらonChangedが呼び出される - @Override - public void onChanged(List activities) { - // 更新したフレンドの再登場,更新してないフレンドの退場 - //更新した人を見つけてFriendIconViewを呼び出して、 - List sortedFriendUserIds = activityViewModel.getSortedFriendUserIds();//アクティビティを更新した最新6人のリスト -// FriendIconView userView = userViews.get(friendId); -// if (userView != null && activities != null && !activities.isEmpty()) { -// //latestは最新のアクティビティを保持する -// Activity latest = activities.get(activities.size() - 1); -// } -// // 最新更新フレンドをリストに追加(最大6人保持) - int size = sortedFriendUserIds.size(); - List latestSix = sortedFriendUserIds.subList(Math.max(size - 6, 0), size); - - synchronized (recentUpdatedFriends) { - if (latestSix.contains(friendId)) { - recentUpdatedFriends.remove(friendId); - recentUpdatedFriends.add(0, friendId); - if (recentUpdatedFriends.size() > 6) { - recentUpdatedFriends.remove(recentUpdatedFriends.size() - 1); - } - } - } -//スレッド処理をいれて更新できるようにする - } - }); - } + // アクティビティ更新の監視は、各FriendIconView作成時に登録する + // (updateActivityView内でLiveData.observe(...)を行う) // for (String friendId : userViews.keySet()) { @@ -390,6 +353,7 @@ for (String friendId : friends) { FriendIconView userView = userViews.get(friendId); //userViews.put(friendId, null); + // 各フレンドのアクティビティLiveDataを取得 MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(friendId); // for (String friendId : sortedFriendUserIds) { @@ -444,6 +408,11 @@ // Mapに登録、画面に追加 userViews.put(friendId, container); + + // フレンドのアクティビティ更新を監視し、吹き出しコメントを更新する + if (activitiesLiveData != null) { + activitiesLiveData.observe(MainActivity.this, container.getActivitiesObserver()); + } // userView = container; // messageList.addView(container);