diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index b268ef3..55829cb 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -4,6 +4,14 @@
+
+
+
+
+
+
+
+
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 3d15caf..3cc9160 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
@@ -17,8 +17,10 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.stream.Collectors;
import retrofit2.Call;
import retrofit2.Callback;
@@ -26,19 +28,14 @@
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;
-/**
- * アクティビティを扱うためのViewModel
- *
- * @author Shohei Yamagiwa
- * @implNote Repositoryは作成せずに、すべてViewModelで処理する
- */
public class ActivityViewModel extends RealTimeViewModel {
private final ActivitiesResource activitiesResource;
private final UserResource userResource;
- private final MutableLiveData myLatestActivityLiveData; // 自分の最新のアクティビティ
- private final Map>> friendToActivitiesLiveData; // <フレンドのユーザーID, フレンドのアクティビティのリスト>
- private final MutableLiveData> friendUserIdsLiveData; // フレンドのユーザーIDのリスト
+ private final MutableLiveData myLatestActivityLiveData;
+ private final Map>> friendToActivitiesLiveData;
+ private final MutableLiveData> friendUserIdsLiveData;
+ private final MutableLiveData> allFriendsLatestActivitiesLiveData;
private final String myUserId;
private final String myToken;
@@ -47,17 +44,10 @@
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);
@@ -65,6 +55,7 @@
friendToActivitiesLiveData = new HashMap<>();
friendUserIdsLiveData = new MutableLiveData<>(List.of());
myLatestActivityLiveData = new MutableLiveData<>(null);
+ allFriendsLatestActivitiesLiveData = new MutableLiveData<>(new ArrayList<>());
userActivityStatusChangeListeners = new ArrayList<>();
}
@@ -76,28 +67,9 @@
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);
}
@@ -107,13 +79,20 @@
}
});
- // 自分のフレンドの最新のアクティビティを取得して更新する
- if (friendUserIdsLiveData.isInitialized() && friendUserIdsLiveData.getValue() != null) {
+ if (friendUserIdsLiveData.getValue() != null) {
for (String userId : friendUserIdsLiveData.getValue()) {
pullLatestActivity(userId, activitiesResource, new ActivityFetchCallback() {
@Override
public void onSuccess(Activity activity) {
- updateFriendToActivitiesLiveData(activity, userId);
+ List currentActivities = allFriendsLatestActivitiesLiveData.getValue();
+ if (currentActivities == null) {
+ currentActivities = new ArrayList<>();
+ }
+ // 既存のリストから同じユーザーIDのアクティビティを削除
+ currentActivities.removeIf(a -> a.getUserId().equals(activity.getUserId()));
+ // 新しいアクティビティを追加
+ currentActivities.add(activity);
+ allFriendsLatestActivitiesLiveData.postValue(currentActivities);
}
@Override
@@ -124,47 +103,19 @@
}
}
- if (friendUserIdsLiveData.isInitialized()) {
- // 最新のフレンドのユーザーIDを取得して更新する
- // TODO: 適切なコールバックを使う必要あり
- pullLatestFriendUserIds(myUserId, myToken);
- }
+ pullLatestFriendUserIds(myUserId, myToken);
};
}
- /**
- * ユーザ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;
-
+ MutableLiveData> userActivitiesLiveData = friendToActivitiesLiveData.computeIfAbsent(userId, k -> new MutableLiveData<>(new ArrayList<>()));
List userActivities = userActivitiesLiveData.getValue();
- if (userActivities == null || userActivities.isEmpty()) {
- userActivitiesLiveData.postValue(List.of(latestActivity));
- } else {
- if (userActivities.equals(List.of(latestActivity))) {
- return;
- }
-
+ if (userActivities == null || userActivities.isEmpty() || !userActivities.get(0).equals(latestActivity)) {
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;
@@ -176,16 +127,16 @@
public void onResponse(@NonNull Call call, @NonNull Response response) {
if (response.isSuccessful()) {
String createdActivityId = response.body();
+ if (createdActivityId == null) return;
Call getActivityCall = activitiesResource.getActivity(userId, createdActivityId);
getActivityCall.enqueue(new Callback() {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
Activity createdActivity = response.body();
- if (createdActivity == null) {
- return;
+ if (createdActivity != null) {
+ myLatestActivityLiveData.postValue(createdActivity);
}
- myLatestActivityLiveData.postValue(createdActivity);
}
@Override
@@ -205,83 +156,40 @@
});
}
- /**
- * 最新のユーザーのアクティビティを取得・更新する
- *
- * @param userId 取得対象のユーザーのID
- * @param resource アクティビティのリソース
- * @param 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) {
- if (response.isSuccessful()) {
- Collection activities = response.body().values(); // アクティビティが存在しない場合は空のリスト
- if (activities == null || activities.isEmpty()) {
- return;
+ if (response.isSuccessful() && response.body() != null) {
+ Collection activities = response.body().values();
+ if (!activities.isEmpty()) {
+ callback.onSuccess(activities.iterator().next());
}
-
- Activity latestActivity = activities.iterator().next();
- callback.onSuccess(latestActivity);
}
}
@Override
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
- * @param token 自分のユーザー認証用トークン
- */
private void pullLatestFriendUserIds(String userId, String token) {
Call> fetchFriendUserIdsCall = userResource.getFriends(userId, token);
fetchFriendUserIdsCall.enqueue(new Callback>() {
@Override
public void onResponse(@NonNull Call> call, @NonNull Response> response) {
- if (response.isSuccessful()) {
-
- // MEMO: 入れ込んだだけ
- // フレンドのIDをアクティビティ更新順に並べ替える
- List friendUserIds = friendUserIdsLiveData.getValue();
- if (friendUserIds == null || !friendUserIds.equals(response.body())) {
+ if (response.isSuccessful() && response.body() != null) {
+ if (!Objects.equals(friendUserIdsLiveData.getValue(), 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()));
}
}
}
@@ -297,23 +205,18 @@
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);
+ return friendToActivitiesLiveData.computeIfAbsent(userId, k -> new MutableLiveData<>());
}
public MutableLiveData> getFriendUserIdsLiveData() {
return friendUserIdsLiveData;
}
+ public MutableLiveData> getAllFriendsLatestActivitiesLiveData() {
+ return allFriendsLatestActivitiesLiveData;
+ }
+
public String getMyUserId() {
return myUserId;
}
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 f6b4111..3a854e6 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
@@ -44,10 +44,7 @@
import com.google.android.material.imageview.ShapeableImageView;
import com.example.tampopo_client.viewmodels.ActivityViewModelFactory;
import com.example.tampopo_client.viewmodels.ChatViewModel;
-import com.example.tampopo_client.viewmodels.ChatViewModelFactory;
import com.example.tampopo_client.viewmodels.NotificationListener;
-import com.example.tampopo_client.viewmodels.UserViewModel;
-import com.google.android.material.imageview.ShapeableImageView;
import java.util.ArrayList;
import java.util.HashMap;
@@ -133,52 +130,13 @@
ChatViewModelFactory factory1 = new ChatViewModelFactory(tampopo.getUserId(), tampopo.getToken(), tampopo.getChatroomId());
chatViewModel = new ViewModelProvider(this, factory1).get(ChatViewModel.class);
- MutableLiveData> friendsLiveData = activityViewModel.getFriendUserIdsLiveData();
-
- friendsLiveData.observe(this, new Observer>() {
+ activityViewModel.getAllFriendsLatestActivitiesLiveData().observe(this, new Observer>() {
@Override
- public void onChanged(List friends) {
- // フレンドの追加と削除
- updateActivityView(friends);
+ public void onChanged(List activities) {
+ updateActivityView(activities);
}
});
-
- for (String friendId : userViews.keySet()) {
- final String updateFriendId = friendId;
- MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId);
- //MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(updateFriendId);
-
- FriendIconView friendView = userViews.get(friendId);
- if (friendView == null) continue;
- //activitiesLiveData.observeForever(friendView);
- activitiesLiveData.observeForever(new Observer>() {
- @Override
- public void onChanged(List activities) {
- // 更新したフレンドの再登場,更新してないフレンドの退場
- //更新した人を見つけてFriendIconViewを呼び出して、
- FriendIconView userView = userViews.get(updateFriendId);
- if (userView != null && activities != null && !activities.isEmpty()) {
- Activity latest = activities.get(activities.size() - 1);
- }
- //フレンドの位置決め
- // 最新更新フレンドをリストに追加(最大6人保持)
- synchronized (recentUpdatedFriends) {
- // すでに存在する場合は削除して再追加(重複防止)
- recentUpdatedFriends.remove(updateFriendId);
- // 先頭に追加(最近更新した人ほど前)
- recentUpdatedFriends.add(0, updateFriendId);
-
- // 6人を超えたら古いものを削除
- if (recentUpdatedFriends.size() > 6) {
- recentUpdatedFriends.remove(recentUpdatedFriends.size() - 1);
- }
- }
-
- }
- });
- }
-
//メイン画面から設定画面への遷移
ImageButton settingButton = (ImageButton) findViewById(R.id.setting);
settingButton.setOnClickListener(new View.OnClickListener() {
@@ -301,60 +259,32 @@
}
}
- private void updateActivityView(List friends) {
- ///natty ユーザごとにコメントの更新をする
- LinearLayout messageList = findViewById(R.id.messageList);
+ private void updateActivityView(List activities) {
ConstraintLayout layout = findViewById(R.id.main);
i = 0;
- for (String friendId : friends) {
-
-// String friendId = entry.getUserId();
-// Activity activity = entry;
+ for (Activity activity : activities) {
+ String friendId = activity.getUserId();
FriendIconView userView = userViews.get(friendId);
- MutableLiveData> activitiesLiveData = activityViewModel.getActivitiesLiveDataFromUserId(friendId);
-
if (userView == null) {
-
// 新しいユーザなので、アイコン+コメントを作成
- FriendIconView container = new FriendIconView(this);
- container.setPadding(16, 16, 16, 16);
- container.setId(View.generateViewId());
+ userView = new FriendIconView(this, friendId, "", chatViewModel);
+ userView.setId(View.generateViewId());
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
);
- container.setLayoutParams(params);
+ userView.setLayoutParams(params);
- layout.addView(container);
-
-// // ユーザのアイコン(固定)
-// ShapeableImageView iconView = new ShapeableImageView(this);
-// iconView.setLayoutParams(new LinearLayout.LayoutParams(100, 100));
-// iconView.setScaleType(ImageView.ScaleType.CENTER_CROP);
-// iconView.setStrokeColor(ContextCompat.getColorStateList(this, R.color.red));
-// iconView.setStrokeWidth(2f);
-// iconView.setShapeAppearanceModel(
-// iconView.getShapeAppearanceModel().toBuilder()
-// .setAllCornerSizes(50) // 丸く
-// .build()
-// );
-//
-// // ユーザIDに応じてアイコンリソースを決定(仮にハードコード or マッピング)
-// iconView.setImageResource(getUserIconResource(friendId)); // ←ここがポイント
-
- // Mapに登録、画面に追加
- userViews.put(friendId, container);
- userView = container;
- //messageList.addView(container);
-
- // TODO: CHANGE
- activitiesLiveData.observeForever(container.getActivitiesObserver());
+ layout.addView(userView);
+ userViews.put(friendId, userView);
}
+ userView.setComment(activity.getText());
+
ConstraintSet set = new ConstraintSet();
set.clone(layout);
int marginTopInPx = (int) TypedValue.applyDimension(
@@ -373,7 +303,7 @@
set.applyTo(layout);
- if(i<6){
+ if(i < 6){
i++;
}
}