package com.example.nemophila;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.nemophila.entities.Account;
import com.example.nemophila.entities.AccountNameJson;
import com.example.nemophila.viewmodels.AccountViewModel;
import com.example.nemophila.viewmodels.FriendViewModel;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FriendActivity extends AppCompatActivity {
private Nemophila nemophila;
private FriendViewModel friendViewModel;
private String uid;
private String token;
private String requestingId;
private String requestingName;
private String searchingId;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private final Handler handler = new Handler();
private String friendIconUrlString;
private String requestingIconUrlString;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_friend);
Button showFriend = findViewById(R.id.showFriend);
Button showRequesting = findViewById(R.id.showRequesting);
RecyclerView friendRecyclerView = findViewById(R.id.friendsList);
LinearLayout requestingConstraintLayout = findViewById(R.id.requestingLayout);
// 初期化
List<FriendDataModel> friendsDataset = new ArrayList<>(); // 1行分の情報を持つDataModelを格納するリスト
RecyclerView rv = findViewById(R.id.friendsList); // recyclerViewを取得
friendViewModel = new ViewModelProvider(this).get(FriendViewModel.class); // ViewModelを取得
nemophila = (Nemophila) this.getApplication();
uid = nemophila.getUid(); // 自身のidを取得
token = nemophila.getToken(); // 自身のtokenを取得
//一行ずつを縦に(LinearLayout)表示するLayoutManagerを宣言
LinearLayoutManager llm = new LinearLayoutManager(this);
// データ1つ1つの区切りが分かるように線を引く
RecyclerView.ItemDecoration itemDecoration =
new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
rv.addItemDecoration(itemDecoration);
rv.setHasFixedSize(true);
rv.setLayoutManager(llm);
// getFriendsの通信が呼び出されて、フレンドの一覧をfriendsDatasetに格納し、Adapterにセットする
FriendActivityAdapter adapter = new FriendActivityAdapter(friendsDataset) {
@Override
void onDeleteClick(View view, int position, FriendDataModel friend) {
new AlertDialog.Builder(FriendActivity.this)
.setTitle("フレンドから" + friend.getName() + "を削除しますか?")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
friendViewModel.deleteFriend(uid, friend.getId(), token);
}
})
.setNegativeButton("キャンセル", null)
.create()
.show();
}
@Override
void onFavoriteClick(View view, int position, FriendDataModel friend, ImageView favorite) {
if (favorite.getVisibility() == View.INVISIBLE) {
favorite.setVisibility(View.VISIBLE);
nemophila.setFavoriteFriends(friend.getId());
} else {
favorite.setVisibility(View.INVISIBLE);
nemophila.removeFavoriteFriends(friend.getId());
System.out.println(nemophila.getFavoriteFriends());
}
}
};
friendViewModel.getFriends(uid); // 自身のフレンドの一覧を取得するメソッドを呼び出す
friendViewModel.getFriendsLiveData().observe(this, new Observer<Collection<AccountNameJson>>() {
@Override
public void onChanged(Collection<AccountNameJson> friends) {
// 以前のデータが残っていると不都合なので、空にしておく
friendsDataset.clear();
for (AccountNameJson friend : friends) {
FriendDataModel data = new FriendDataModel();
data.setName(friend.getName());
data.setId(friend.getUid());
//url作る
friendIconUrlString = "http://nitta-lab-www.is.konan-u.ac.jp/nemophila-data/icon" + friend.getUid() + ".jpg";
data.setUrl(friendIconUrlString);
executor.execute(() -> {
try{
URL url = new URL(data.getUrl());
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.connect();
InputStream is = con.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
handler.post(() -> {
data.setIcon(bitmap);
adapter.notifyItemChanged(adapter.getPosition(data));
});
is.close();
con.disconnect();
}catch (Exception e){
e.printStackTrace();
}
});
friendsDataset.add(data);
}
adapter.setList(friendsDataset);
rv.setAdapter(adapter);
}
});
//idからアカウント名を検索するためのAccountViewModelを宣言しておく
AccountViewModel accountViewModel = new ViewModelProvider(this).get(AccountViewModel.class);
//フレンド検索ボタン
Button requestingButton = findViewById(R.id.requestingSearchButton);
requestingButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//入力されたIDを取得
EditText editSearchId = findViewById(R.id.inputRequestingId);
searchingId = editSearchId.getText().toString();
//取得したIDからアカウントを読み込む(検索用のOnChangedへ)
accountViewModel.fetchAccount(searchingId);
}
});
//検索用LiveDataへの購読
accountViewModel.getAccountLiveData().observe(FriendActivity.this, new Observer<Account>() {
//ViewModelからアカウントが返ってくれば(データ変更があれば)実行
@Override
public void onChanged(Account user) {
if(user == null){
new AlertDialog.Builder(FriendActivity.this)
.setTitle("IDが間違っています")
.setPositiveButton("OK", null)
.create()
.show();
}else {
requestingName = (user.getName());
//申請を送るダイアログ
RequestingDialogFragment dialog = new RequestingDialogFragment(FriendActivity.this);
//名前を渡す
Bundle args = new Bundle();
args.putString("message", requestingName);
dialog.setArguments(args);
//ダイアログの表示
dialog.show(getSupportFragmentManager(), "Requesting_dialog");
//OK押したら申請するメソッドにuid、requestingId、tokenを渡す
}
}
});
//RecyclerView(表示の設定、直接表示するところはLivedataを購読しているonChanged内に)
List<RequestingDataModel> requestingDataList = new ArrayList<>();
//xmlからrvにRecyclerViewを取得
RecyclerView rv_r = (RecyclerView) findViewById(R.id.requestingList);
//アダプターを宣言し、削除ボタンを押したときの処理をオーバーライド
FriendActivity.RequestingAdapter adapter_r = new FriendActivity.RequestingAdapter(requestingDataList){
@Override
void onDeleteClick_r(View view, int position, FriendActivity.RequestingDataModel user) {
new AlertDialog.Builder(FriendActivity.this)
.setTitle(user.getName() + "さんへの申請を削除しますか?")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(FriendActivity.this, user.getName(), Toast.LENGTH_SHORT).show();
friendViewModel.deleteRequesting(uid, user.getId(), token);
}
})
.setNegativeButton("キャンセル", null)
.create()
.show();
}
};
//一行ずつを縦に(LinearLayout)表示するLayoutManagerを宣言
LinearLayoutManager llm_r = new LinearLayoutManager(this);
//データごとの区切り線を入れる
RecyclerView.ItemDecoration itemDecoration_r =
new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
rv_r.addItemDecoration(itemDecoration_r);
rv_r.setHasFixedSize(true);
rv_r.setLayoutManager(llm_r);
//申請先の一覧のLiveDataへの購読
friendViewModel.getRequestingLiveData().observe(this, new Observer<Collection<AccountNameJson>>() {
//データに変更があった時実行
@Override
public void onChanged(Collection<AccountNameJson> requestingUsers) {
//表示用のDataListを一旦クリアし、LiveDataから受け取ったデータを一つずつセット(重複しないように)
requestingDataList.clear();
//受け取ったLivedataの要素分繰り返し、セット
for (AccountNameJson user: requestingUsers) {
//dataを宣言 dataに投稿の必要なデータをセットし、それをpostsDatasetに追加してリストを作る
RequestingDataModel data = new RequestingDataModel();
data.setName(user.getName());
data.setId(user.getUid());
//url作る
requestingIconUrlString = "http://nitta-lab-www.is.konan-u.ac.jp/nemophila-data/icon" + user.getUid() + ".jpg";
data.setUrl(requestingIconUrlString);
executor.execute(() -> {
try{
URL url = new URL(data.getUrl());
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.connect();
InputStream is = con.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
handler.post(() -> {
data.setIcon(bitmap);
adapter_r.notifyItemChanged(adapter_r.getPosition(data));
});
is.close();
con.disconnect();
}catch (Exception e){
e.printStackTrace();
}
});
//投稿一つの情報がdataに全部セットされたらDatasetに追加
requestingDataList.add(0, data);
}
//onChange内に書くべき表示部分
adapter_r.setList(requestingDataList);
rv_r.setAdapter(adapter_r);
}
});
// フレンド一覧と申請先一覧の画面切り替え
showFriend.setOnClickListener(v2 -> {
friendRecyclerView.setVisibility(View.VISIBLE);
requestingConstraintLayout.setVisibility(View.INVISIBLE);
friendViewModel.getFriends(uid);
});
showRequesting.setOnClickListener(v3 -> {
friendRecyclerView.setVisibility(View.INVISIBLE);
requestingConstraintLayout.setVisibility(View.VISIBLE);
friendViewModel.getRequesting(uid);
});
// MyPageActivityに戻る
Button closeBtn = findViewById(R.id.close);
closeBtn.setOnClickListener(d -> finish());
}
// ----------- FriendのRecyclerView用の内部クラス ------------//
// Adapter
abstract public class FriendActivityAdapter extends RecyclerView.Adapter<FriendsViewHolder> {
private List<FriendDataModel> friendData;
public FriendActivityAdapter(List<FriendDataModel> friendData) {
this.friendData = friendData;
}
public int getPosition(FriendDataModel d) {
return friendData.indexOf(d);
}
public void setList(List<FriendDataModel> friendData) {
this.friendData = friendData;
}
@NonNull
@Override
public FriendsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int ViewType) {
// layoutXMLからViewを生成
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.friend_list_item, parent,false);
// ViewHolderを生成
FriendsViewHolder vh = new FriendsViewHolder(inflate);
// 削除ボタンを押したときのイベントを登録
vh.deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = vh.getBindingAdapterPosition();
// 処理はonDeleteClick()に丸投げ
onDeleteClick(v, position, friendData.get(position));
}
});
// お気に入りに追加したときのイベントを登録
vh.favoriteOutline.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = vh.getBindingAdapterPosition();
// 処理はonFavoriteClick()に丸投げ
onFavoriteClick(v, position, friendData.get(position), vh.favorite);
}
});
return vh;
}
@Override
public void onBindViewHolder(@NonNull FriendsViewHolder holder, int position) {
// 後からアイコンの登録をできるようにする
holder.nameView.setText(friendData.get(position).getName());
holder.iconView.setImageBitmap(friendData.get(position).getIcon());
if (nemophila.getFavoriteFriends().contains(friendData.get(position).getId())) {
holder.favorite.setVisibility(View.VISIBLE);
}
}
@Override
public int getItemCount() {
return friendData.size();
}
abstract void onDeleteClick(View view, int position, FriendDataModel friend);
abstract void onFavoriteClick(View view, int position, FriendDataModel friend, ImageView favorite);
}
// ViewHolder
public class FriendsViewHolder extends RecyclerView.ViewHolder {
public ImageView favorite;
public ImageButton favoriteOutline;
public ImageView iconView;
public TextView nameView;
public Button deleteButton;
public FriendsViewHolder(@NonNull View itemView) {
super(itemView);
favorite = itemView.findViewById(R.id.favorite);
favoriteOutline = itemView.findViewById(R.id.favorite_outline);
iconView = itemView.findViewById(R.id.friendIcon);
nameView = itemView.findViewById(R.id.friendName);
deleteButton = itemView.findViewById(R.id.friendDelete);
}
}
// DataModel
public static class FriendDataModel {
private String name;
private String id;
private Bitmap icon;
private String url;
public String getName() {
return name;
}
public String getId() {
return id;
}
public Bitmap getIcon() { return icon; }
public String getUrl() { return url; }
public void setName(String name) {
this.name = name;
}
public void setId(String id) { this.id = id;}
public void setIcon(Bitmap icon){ this.icon = icon; }
public void setUrl(String url) { this.url = url; }
}
// ----------- RequestingのRecyclerView用の内部クラス ------------//
//Adapter
public class RequestingAdapter extends RecyclerView.Adapter<FriendActivity.RequestingViewHolder> {
private List<RequestingDataModel> list;
public RequestingAdapter(List<RequestingDataModel> list) {
this.list =list;
}
public int getPosition(RequestingDataModel d) { return list.indexOf(d); }
public void setList(List<RequestingDataModel> list) {
this.list = list;
}
@NonNull
@Override
public FriendActivity.RequestingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//1データあたりのレイアウトを読み込み、ビューホルダーを宣言
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_requesting_activity, parent,false);
FriendActivity.RequestingViewHolder vh = new FriendActivity.RequestingViewHolder(inflate);
// リスト内の削除ボタンを押した時の処理
vh.deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = vh.getBindingAdapterPosition();
// 処理はonDeleteClickに
onDeleteClick_r(v, position, list.get(position));
}
});
return vh;
}
@Override
public void onBindViewHolder(@NonNull FriendActivity.RequestingViewHolder holder, int position) {
holder.nameView.setText(list.get(position).getName());
holder.iconView.setImageBitmap(list.get(position).getIcon());
}
@Override
public int getItemCount() {
return list.size();
}
void onDeleteClick_r(View view, int position, FriendActivity.RequestingDataModel requesting) {
// このメソッドをActivity内でオーバーライドして、クリックイベントの処理を設定する
}
}
//ViewHolder
public class RequestingViewHolder extends RecyclerView.ViewHolder {
public TextView nameView;
public ImageView iconView;
public Button deleteButton;
public RequestingViewHolder(@NonNull View itemView) {
super(itemView);
nameView = itemView.findViewById(R.id.requestingName);
iconView = itemView.findViewById(R.id.requestingIcon);
deleteButton = itemView.findViewById(R.id.requestingDeleteButton);
}
}
//DataModel
public static class RequestingDataModel {
private String name;
private String id;
private Bitmap icon;
private String url;
public String getName() {
return name;
}
public String getId() {
return id;
}
public Bitmap getIcon() { return icon; }
public String getUrl() { return url; }
public void setName(String name) {
this.name = name;
}
public void setId(String id){
this.id = id;
}
public void setIcon(Bitmap icon) { this.icon = icon; }
public void setUrl(String url) { this.url = url; }
}
//ダイアログでOKを押した時に呼び出される フレンド申請を送るメソッド
public void putRequesting(){
requestingId = searchingId;
friendViewModel.putRequesting(uid, requestingId, requestingName, token);
}
}