diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a3f844e..341686f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,14 +15,15 @@
android:theme="@style/Theme.Tampopoclient"
android:usesCleartextTraffic="true"
tools:targetApi="31">
-
-
-
-
+
+
+
@@ -46,19 +47,18 @@
-
-
-
+
+
-
-
-
-
-
+
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/java/com/example/tampopo_client/models/FriendRequest.java b/app/src/main/java/com/example/tampopo_client/models/FriendRequest.java
index 939f0b7..4f8f14b 100644
--- a/app/src/main/java/com/example/tampopo_client/models/FriendRequest.java
+++ b/app/src/main/java/com/example/tampopo_client/models/FriendRequest.java
@@ -5,6 +5,9 @@
private String senderId;
private String receiverId;
+ public FriendRequest(){
+ //デフォルトコンストラクタを追加しました
+ }
public FriendRequest(String senderId, String receiverId) {
this.senderId = senderId;
this.receiverId = receiverId;
diff --git a/app/src/main/java/com/example/tampopo_client/resources/FriendRequestsResource.java b/app/src/main/java/com/example/tampopo_client/resources/FriendRequestsResource.java
index d119b3d..b82d1ae 100644
--- a/app/src/main/java/com/example/tampopo_client/resources/FriendRequestsResource.java
+++ b/app/src/main/java/com/example/tampopo_client/resources/FriendRequestsResource.java
@@ -19,7 +19,7 @@
//このAPIではリクエストのボディをx-www-form-urlencoded という形式で送ります
@FormUrlEncoded
@POST("friend-requests")
- Call postFriendRequest(
+ Call postFriendRequest(
@Field("sender-id") String senderId,
@Field("receiver-id") String receiverId,
@Field("token") String token
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 5a2e999..2c455f2 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
@@ -4,13 +4,13 @@
import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
import com.example.tampopo_client.models.Activity;
import com.example.tampopo_client.resources.ActivitiesResource;
+import com.example.tampopo_client.resources.UserResource;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import retrofit2.Call;
import retrofit2.Callback;
@@ -24,22 +24,60 @@
* @author Shohei Yamagiwa
* @implNote Repositoryは作成せずに、すべてViewModelで処理する
*/
-public class ActivityViewModel extends ViewModel {
+public class ActivityViewModel extends RealTimeViewModel {
private final ActivitiesResource activitiesResource;
+ private final UserResource userResource;
- private final MutableLiveData> activitiesLiveData;
+ private final Map>> friendToActivitiesLiveData; // key=userId
+ private final MutableLiveData> friendUserIdsLiveData; // フレンドのユーザーIDのリスト
+ private final MutableLiveData myLatestActivityLiveData; // 自分の最新のアクティビティ
- public ActivityViewModel() {
- final Retrofit retrofit = new Retrofit.Builder()
- .baseUrl("http://nitta-lab-www.is.konan-u.ac.jp/tampopo/")
- .addConverterFactory(JacksonConverterFactory.create())
- .build();
+ private final String userId;
+ private final String token;
+
+ public ActivityViewModel(String userId, String token) {
+ this.userId = userId;
+ this.token = token;
+
+ // 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);
- activitiesLiveData = new MutableLiveData<>(List.of());
+ friendToActivitiesLiveData = Map.of();
+ friendUserIdsLiveData = new MutableLiveData<>(List.of());
+ myLatestActivityLiveData = new MutableLiveData<>();
+ }
+
+ @Override
+ public Runnable onUpdate() {
+ return () -> {
+ if (friendToActivitiesLiveData == null || friendUserIdsLiveData == null || myLatestActivityLiveData == null) {
+ return;
+ }
+
+ // 最新のアクティビティを取得して更新する
+ if (friendUserIdsLiveData.isInitialized() && friendUserIdsLiveData.getValue() != null) {
+ for (String userId : friendUserIdsLiveData.getValue()) {
+ pullLatestActivity(userId, activitiesResource, friendToActivitiesLiveData);
+ }
+ }
+
+ // 最新のフレンドのユーザーIDを取得して更新する
+ if (friendUserIdsLiveData.isInitialized()) {
+ pullLatestFriendUserIds(userId, token);
+ }
+
+ // Logging
+ Log.d(ActivityViewModel.class.getSimpleName(), "Polling data from the server.");
+ };
}
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
@@ -47,18 +85,16 @@
if (response.isSuccessful()) {
String createdActivityId = response.body();
- // TODO: 仮作成なので改善必須
+ // TODO: 仮作成なので改善したい
Call getActivityCall = activitiesResource.getActivity(userId, createdActivityId);
getActivityCall.enqueue(new Callback() {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
- List activities = activitiesLiveData.getValue();
- if (activities == null) {
- activities = new ArrayList<>();
- }
Activity createdActivity = response.body();
- activities.add(createdActivity);
- activitiesLiveData.postValue(activities);
+ if (createdActivity == null) {
+ return;
+ }
+ myLatestActivityLiveData.postValue(createdActivity);
}
@Override
@@ -73,12 +109,101 @@
@Override
public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Log.e(ActivityViewModel.class.getSimpleName(), "An error has occurred.", t);
+ Log.e(ActivityViewModel.class.getSimpleName(), "An error has occurred while creating new activity.", t);
}
});
}
- public MutableLiveData> getActivitiesLiveData() {
- return activitiesLiveData;
+ /**
+ * 最新のユーザーのアクティビティを取得・更新する
+ *
+ * @param userId 取得対象のユーザーのID
+ * @param resource アクティビティのリソース
+ * @param friendToActivitiesLiveData フレンドのユーザーIDからアクティビティへの写像のライブデータ
+ */
+ private void pullLatestActivity(String userId, ActivitiesResource resource, Map>> friendToActivitiesLiveData) {
+ Call> fetchActivityCall = resource.getActivities(userId, "LATEST");
+ fetchActivityCall.enqueue(new Callback>() {
+ @Override
+ public void onResponse(@NonNull Call> call, @NonNull Response> response) {
+ if (response.isSuccessful()) {
+ List fetchedActivities = response.body(); // アクティビティが存在しない場合は空のリスト
+ if (fetchedActivities == null) {
+ 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);
+ }
+ }
+ }
+
+ @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);
+ }
+ });
+ }
+
+ /**
+ * 最新の自分のフレンドのユーザー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()) {
+ friendUserIdsLiveData.postValue(response.body());
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
+ Log.e(ActivityViewModel.class.getSimpleName(), "An error has occurred while fetching all friends' id.", t);
+ }
+ });
+ }
+
+ public MutableLiveData getMyLatestActivityLiveData() {
+ return myLatestActivityLiveData;
+ }
+
+ public MutableLiveData> getActivitiesLiveDataFromUserId(String userId) {
+ return friendToActivitiesLiveData.get(userId);
+ }
+
+ public MutableLiveData> getFriendUserIdsLiveData() {
+ return friendUserIdsLiveData;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public String getToken() {
+ return token;
}
}
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/ActivityViewModelFactory.java b/app/src/main/java/com/example/tampopo_client/viewmodels/ActivityViewModelFactory.java
new file mode 100644
index 0000000..f52c8bf
--- /dev/null
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/ActivityViewModelFactory.java
@@ -0,0 +1,36 @@
+package com.example.tampopo_client.viewmodels;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * ViewModelのライフサイクルの関係で、インスタンスを生成するためのFactoryクラスが必要
+ *
+ * @author Shohei Yamagiwa
+ */
+public class ActivityViewModelFactory implements ViewModelProvider.Factory {
+ private final String userId;
+ private final String token;
+
+ public ActivityViewModelFactory(String userId, String token) {
+ this.userId = userId;
+ this.token = token;
+ }
+
+ @NonNull
+ @Override
+ public T create(@NonNull Class modelClass) {
+ if (modelClass.isAssignableFrom(ActivityViewModel.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/ChatViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModel.java
new file mode 100644
index 0000000..3f0ca2c
--- /dev/null
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/ChatViewModel.java
@@ -0,0 +1,33 @@
+package com.example.tampopo_client.viewmodels;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ChatViewModel extends RealTimeViewModel {
+ private final List notificationListeners = new ArrayList<>();
+
+ private static final double NOTIFICATION_RECEIVE_PROBABILITY = 0.01;
+
+ @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());
+ }
+ };
+ }
+
+ public void addNotificationListener(NotificationListener listener) {
+ notificationListeners.add(listener);
+ }
+
+ public void clearNotificationListener() {
+ notificationListeners.clear();
+ }
+}
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 275eb6b..0b01c76 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
@@ -6,6 +6,7 @@
import com.example.tampopo_client.models.FriendRequest;
import com.example.tampopo_client.resources.FriendRequestsResource;
+import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
@@ -13,6 +14,7 @@
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;
+import retrofit2.converter.scalars.ScalarsConverterFactory;
public class FriendReceivedRequestViewModel extends ViewModel {
//サーバー(API)と通信するためのツール
@@ -28,10 +30,11 @@
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<>();
+ this.receivedRequests = new MutableLiveData<>(new ArrayList<>());
this.operationResult = new MutableLiveData<>();
}
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/FriendSentRequestViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/FriendSentRequestViewModel.java
index b7a0baa..3cc0a89 100644
--- a/app/src/main/java/com/example/tampopo_client/viewmodels/FriendSentRequestViewModel.java
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/FriendSentRequestViewModel.java
@@ -13,6 +13,7 @@
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;
+import retrofit2.converter.scalars.ScalarsConverterFactory;
public class FriendSentRequestViewModel extends ViewModel {
// サーバー(API)と通信するためのツール
@@ -31,6 +32,7 @@
public FriendSentRequestViewModel() {
this.retrofit = new Retrofit.Builder()
.baseUrl("http://nitta-lab-www.is.konan-u.ac.jp/tampopo/")
+ .addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.build();
@@ -51,7 +53,7 @@
// サーバーから送信済みフレンドリクエスト一覧を取得してキャッシュに保存
public void loadSentRequests(String token) {
Call> call = friendRequestsResource.getFriendRequests(token);
-
+// フレンド一覧をサーバーからもらう時にエラーが起きている
call.enqueue(new Callback>() {
@Override
public void onResponse(Call> call, Response> response) {
@@ -75,11 +77,11 @@
// サーバーにフレンド申請を送信するメソッド
public void sendFriendRequest(String senderId, String receiverId, String token) {
- Call call = friendRequestsResource.postFriendRequest(token, senderId, receiverId);
+ Call call = friendRequestsResource.postFriendRequest(senderId, receiverId, token);
- call.enqueue(new Callback() {
+ call.enqueue(new Callback() {
@Override
- public void onResponse(Call call, Response response) {
+ public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
//Retrofitでサーバーにリクエストを送った後、その結果が帰ってくる。成功
operationResult.setValue("Friend request sent successfully.");
@@ -95,7 +97,7 @@
}
@Override
- public void onFailure(Call call, Throwable t) {
+ public void onFailure(Call call, Throwable t) {
operationResult.setValue("Network error: " + t.getMessage());
System.out.println("Network error: " + t);
}
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/NotificationListener.java b/app/src/main/java/com/example/tampopo_client/viewmodels/NotificationListener.java
new file mode 100644
index 0000000..772483c
--- /dev/null
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/NotificationListener.java
@@ -0,0 +1,5 @@
+package com.example.tampopo_client.viewmodels;
+
+public interface NotificationListener {
+ void onNotificationReceived();
+}
diff --git a/app/src/main/java/com/example/tampopo_client/viewmodels/RealTimeViewModel.java b/app/src/main/java/com/example/tampopo_client/viewmodels/RealTimeViewModel.java
new file mode 100644
index 0000000..c56ac08
--- /dev/null
+++ b/app/src/main/java/com/example/tampopo_client/viewmodels/RealTimeViewModel.java
@@ -0,0 +1,52 @@
+package com.example.tampopo_client.viewmodels;
+
+import androidx.lifecycle.ViewModel;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@code onUpdate()}が1秒毎に呼び出されます。
+ *
+ * @author Shohei Yamagiwa
+ */
+public abstract class RealTimeViewModel extends ViewModel {
+ private final ScheduledExecutorService updateScheduler;
+ private ScheduledFuture> updateTask;
+
+ public RealTimeViewModel() {
+ updateScheduler = Executors.newSingleThreadScheduledExecutor();
+ }
+
+ public abstract Runnable onUpdate();
+
+ @Override
+ protected void onCleared() {
+ super.onCleared();
+
+ stopUpdating();
+ }
+
+ /**
+ * 定期的に{@code onUpdate()}を呼び出す
+ *
+ * @param delay 定期実行の間隔(秒)
+ */
+ public void startUpdating(long delay) {
+ if (updateTask != null && !updateTask.isDone()) {
+ return;
+ }
+ updateTask = updateScheduler.scheduleWithFixedDelay(this.onUpdate(), 0, delay, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 定期実行を停止する
+ */
+ public void stopUpdating() {
+ if (updateScheduler != null) {
+ updateScheduler.shutdownNow();
+ }
+ }
+}
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
new file mode 100644
index 0000000..c038a2d
--- /dev/null
+++ b/app/src/main/java/com/example/tampopo_client/views/FriendIconView.java
@@ -0,0 +1,279 @@
+package com.example.tampopo_client.views;
+
+import static androidx.core.content.ContextCompat.startActivity;
+
+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.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.example.tampopo_client.R;
+import com.google.android.material.imageview.ShapeableImageView;
+
+/**
+ * TODO: document your custom view class.
+ */
+public class FriendIconView extends FrameLayout {
+ 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;
+ private ShapeableImageView mFriendIcon;
+ private ImageView mFriendCommentImage;
+ private TextView mFriendComment;
+ private TextView mFriendNickname;
+ private ImageView mFriendChatNotification;
+ private boolean chatNotification = false;
+
+ public FriendIconView(Context context) {
+ super(context);
+ init(null, 0);
+ }
+
+ public FriendIconView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ public FriendIconView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(attrs, defStyle);
+ }
+
+ private void init(AttributeSet attrs, int defStyle) {
+ 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);
+ mFriendIcon = findViewById(R.id.friend_icon);
+ mFriendChatNotification = findViewById(R.id.chat_notification);
+
+ //true(チャット通知が来た時)なら表示
+ if(chatNotification){
+ mFriendChatNotification.setVisibility(View.VISIBLE);
+ }
+ //false(チャット通知が来ていない)なら非表示
+ else{
+ mFriendChatNotification.setVisibility(View.GONE);
+ }
+
+ //iconを押したらチャットを始めることができる(チャットのダイアログができたらFriendActivityを変更)
+ mFriendIcon.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ Context ctx = getContext();
+ Intent intent = new Intent(ctx, FriendActivity. class);
+ ctx.startActivity(intent);
+ }
+ });
+// 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);
+// }
+
+// // 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();
+//
+ }
+
+ public void setNickname(String nickname) {
+ if (mFriendNickname != null) {
+ mFriendNickname.setText(nickname);
+ }
+ }
+
+ public void setImageResource(int resId) {
+ if (mFriendIcon != null) {
+ mFriendIcon.setImageResource(resId);
+ }
+ }
+
+ public void setComment(String comment){
+ if(mFriendComment != null){
+ int comment_length = comment.length();
+ if (comment_length > 20) {
+ mFriendComment.setTextSize(7);
+ } else if (comment_length > 10) {
+ mFriendComment.setTextSize(10);
+ } else {
+ mFriendComment.setTextSize(12);
+ }
+ mFriendComment.setText(comment);
+ }
+ }
+
+ public void setChatNotification(boolean chat){
+ //true(チャット通知が来た時)なら表示
+ if(chat){
+ mFriendChatNotification.setVisibility(View.VISIBLE);
+ }
+ //false(チャット通知が来ていない)なら非表示
+ 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;
+ }
+}
\ 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 72f9525..20e07a1 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
@@ -15,35 +15,41 @@
import android.view.ViewGroup;
import com.example.tampopo_client.R;
+import com.example.tampopo_client.Tampopo;
import com.example.tampopo_client.models.FriendRequest;
+import com.example.tampopo_client.viewmodels.FriendSentRequestViewModel;
import com.example.tampopo_client.views.placeholder.FriendRequestContent;
+import com.example.tampopo_client.viewmodels.FriendViewModel;
import com.example.tampopo_client.viewmodels.FriendReceivedRequestViewModel;
+import java.util.ArrayList;
import java.util.List;
/**
- * A fragment representing a list of Items.
+ * 友達申請(受信リスト)を表示するための Fragment クラス
*/
public class FriendReceivedFragment extends Fragment {
- // TODO: Customize parameter argument names
+ // RecyclerView を縦に並べるか、グリッドで並べるかを制御するためのカラム数
private static final String ARG_COLUMN_COUNT = "column-count";
// TODO: Customize parameters
- private int mColumnCount = 1;
+ private int mColumnCount = 1; // デフォルトは1列(縦方向リスト)
- /**
- * Mandatory empty constructor for the fragment manager to instantiate the
- * fragment (e.g. upon screen orientation changes).
- */
+ // アプリ全体で共有するクラス(ユーザー情報やトークンを持っている)
+ private Tampopo tampopo;
+ // RecyclerView のアダプタ(友達申請を表示する)
+ private MyFriendRequestRecyclerViewAdapter adapter;
+
+ // デフォルトのコンストラクタ(Fragmentは必須)
public FriendReceivedFragment() {
}
- // TODO: Customize parameter initialization
+ // この Fragment をインスタンス化するときに、カラム数を指定するためのファクトリーメソッド
@SuppressWarnings("unused")
public static FriendReceivedFragment newInstance(int columnCount) {
FriendReceivedFragment fragment = new FriendReceivedFragment();
Bundle args = new Bundle();
- args.putInt(ARG_COLUMN_COUNT, columnCount);
+ args.putInt(ARG_COLUMN_COUNT, columnCount); // 引数に列数を渡す
fragment.setArguments(args);
return fragment;
}
@@ -52,45 +58,66 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // newInstance で渡された引数を取り出す
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
}
+ //Fragment のレイアウトを作成する部分
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
+ // レイアウト XML を読み込む
View view = inflater.inflate(R.layout.fragment_friend_received_list, container, false);
+ // ViewModel を取得(友達関連の操作をまとめた ViewModel)
+ FriendViewModel friendViewModel = new ViewModelProvider(this).get(FriendViewModel.class);
+
+ // Application クラスからユーザー情報を取得
+ tampopo = (Tampopo) getActivity().getApplication();
+ String receiverId = tampopo.getUserId(); // 自分のユーザーID
+ String token = tampopo.getToken(); // 認証トークン
+
+
// Add some sample items.
// for (int i = 1; i <= 30; i++)
// FriendRequestContent.addItem(new FriendRequestContent.FriendRequestItem(Integer.toString(i), "ユーザ名" + i));
- // Set the adapter
+ // RecyclerView の初期化
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
+ // 1列なら縦スクロールリスト、2列以上ならグリッド表示
if (mColumnCount <= 1) {
recyclerView.setLayoutManager(new LinearLayoutManager(context));
} else {
recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
}
- recyclerView.setAdapter(new MyFriendRequestRecyclerViewAdapter(FriendRequestContent.ITEMS));
+ // アダプタを生成してセット(最初は空のリストを渡す)
+ adapter = new MyFriendRequestRecyclerViewAdapter(new ArrayList<>(), friendViewModel, receiverId, token);
+ recyclerView.setAdapter(adapter);
}
return view;
}
+ //View が作成されたあとに呼ばれる。ここで LiveData の監視を始める。
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ // 受信した友達申請を管理する ViewModel を取得
FriendReceivedRequestViewModel friendReceivedRequestViewModel = new ViewModelProvider(this).get(FriendReceivedRequestViewModel.class);
+ // サーバーから受信した友達リクエスト一覧をロード
+ friendReceivedRequestViewModel.loadReceivedRequests(tampopo.getToken());
+ // LiveData を監視して、データが変わったら RecyclerView に反映
friendReceivedRequestViewModel.getReceivedRequestsLiveData().observe(getViewLifecycleOwner(), new Observer>() {
// LiveData に変更があったとき(新しい友達リクエストのリストが届いたとき)に呼ばれるメソッド
@Override
public void onChanged(List friendRequests) {
- for (FriendRequest f: friendRequests) {
- FriendRequestContent.addItem(new FriendRequestContent.FriendRequestItem(f.getSenderId(), "ユーザー名"));
+ if(adapter != null) {
+ adapter.setItems(friendRequests);
+ adapter.notifyDataSetChanged();
}
}
});
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 4553ea6..7228d1c 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
@@ -10,6 +10,7 @@
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
+import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AlertDialog;
@@ -17,19 +18,27 @@
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
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.UserViewModel;
+import com.example.tampopo_client.viewmodels.ActivityViewModelFactory;
+import com.example.tampopo_client.viewmodels.ChatViewModel;
+import com.example.tampopo_client.viewmodels.NotificationListener;
-public class MainActivity extends AppCompatActivity {
+import java.util.Map;
+
+public class MainActivity extends AppCompatActivity implements NotificationListener {
private EditText editMessage;
private ImageButton sendButton;
private GridView wordGroup;
private LinearLayout messageList;
+ //private List friendIds = List.of();
//アクティビティの選択肢
private String[] words = {"ひまnow", "あそぼ!", "そろそろ会いたない〜?", "勉強なう", "電話しよ~", "お風呂入ってくる~", "今暇だよー!", "いそがしい~!!"};
private Button openDialogButton;
@@ -37,6 +46,7 @@
ActivityViewModel activityViewModel;
Tampopo tampopo;
+ private ChatViewModel chatViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -58,17 +68,41 @@
}
});
- //activityViewModelを宣言する
- activityViewModel = new ViewModelProvider(this).get(ActivityViewModel.class);
//tampopoを宣言する
tampopo = (Tampopo) getApplication();
+ //activityViewModelを宣言する
+ 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);
+
+
+// MutableLiveData>friendUserIdsLiveDate = activityViewModel.getFriendUserIdsLiveData();
+// friendUserIdsLiveDate.observe(this, new Observer>() {
+// @Override
+// public void onChanged(List friendLive) {
+// if(friendLive != null){
+// friendIds = friendLive;
+// updateActivityView(activityViewModel.getActivitiesLiveData().getValue());
+// }
+// }
+// });
+
+ MutableLiveData