package org.ntlab.irisclient;
import static android.os.Looper.getMainLooper;
import static android.view.View.INVISIBLE;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.core.os.HandlerCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import org.ntlab.irisclient.models.Drawing;
import org.ntlab.irisclient.resources.GameRest;
import org.ntlab.irisclient.viewmodels.GameViewModel;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
public class DrawingCardFragment extends Fragment {
private ImageButton[] imageButtons;
private ImageView[] backColors;
private Resources resources;
private GameViewModel gameViewModel;
private Boolean isMaster;
private String myTeam;
private String nowTurn;
private String rid;
private Integer turnState = 1; // 0がヒント入力中
private Integer OpenRedCard = 0;
private Integer OpenBlueCard = 0;
// ロングタップで表示させるために必要。非同期で値が格納され、順番通りに保存されないからHashMapにしている
private Map<Integer, Bitmap> bmImages = new HashMap<>();
// 下はテストが動くようになったら削除する
private Map<Integer, Drawing> drawingList; //<dno, drawingのURL>
private List<Integer> map; //cno順にdnoを管理(要するに絵の並び)
private List<String> colorList; //cno順にr,g,b,dを管理:カードごとの色
private List<Boolean> nowOpenList;
private List<Boolean> nowQList;
// コンストラクタ
public static DrawingCardFragment newInstance(String str){
// インスタンス生成
DrawingCardFragment fragment = new DrawingCardFragment();
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Iris iris = (Iris) this.getActivity().getApplication();
rid = iris.getRid();
gameViewModel = new ViewModelProvider(this).get(GameViewModel.class);
gameViewModel.start(500, iris);
gameViewModel.setRid(rid);
System.out.println(gameViewModel.getImageLiveData());
resources = getResources();
View view = inflater.inflate(R.layout.fragment_card_drawing, container, false);
// 現在のopenListを記録
nowOpenList = new ArrayList<Boolean>(){
{
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
}
};
// 現在のQListを記録
nowQList = new ArrayList<Boolean>(){
{
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
add(false);
}
};
// ImageButton16個の型を使いまわしやすいように配列で使用
imageButtons = new ImageButton[] {
(ImageButton) view.findViewById(R.id.imageButton0),
(ImageButton) view.findViewById(R.id.imageButton1),
(ImageButton) view.findViewById(R.id.imageButton2),
(ImageButton) view.findViewById(R.id.imageButton3),
(ImageButton) view.findViewById(R.id.imageButton4),
(ImageButton) view.findViewById(R.id.imageButton5),
(ImageButton) view.findViewById(R.id.imageButton6),
(ImageButton) view.findViewById(R.id.imageButton7),
(ImageButton) view.findViewById(R.id.imageButton8),
(ImageButton) view.findViewById(R.id.imageButton9),
(ImageButton) view.findViewById(R.id.imageButton10),
(ImageButton) view.findViewById(R.id.imageButton11),
(ImageButton) view.findViewById(R.id.imageButton12),
(ImageButton) view.findViewById(R.id.imageButton13),
(ImageButton) view.findViewById(R.id.imageButton14),
(ImageButton) view.findViewById(R.id.imageButton15)
};
backColors = new ImageView[]{
(ImageView) view.findViewById(R.id.backColour0),
(ImageView) view.findViewById(R.id.backColour1),
(ImageView) view.findViewById(R.id.backColour2),
(ImageView) view.findViewById(R.id.backColour3),
(ImageView) view.findViewById(R.id.backColour4),
(ImageView) view.findViewById(R.id.backColour5),
(ImageView) view.findViewById(R.id.backColour6),
(ImageView) view.findViewById(R.id.backColour7),
(ImageView) view.findViewById(R.id.backColour8),
(ImageView) view.findViewById(R.id.backColour9),
(ImageView) view.findViewById(R.id.backColour10),
(ImageView) view.findViewById(R.id.backColour11),
(ImageView) view.findViewById(R.id.backColour12),
(ImageView) view.findViewById(R.id.backColour13),
(ImageView) view.findViewById(R.id.backColour14),
(ImageView) view.findViewById(R.id.backColour15)
};
gameViewModel.getImageLiveData().observe(
getViewLifecycleOwner(),
gameJsonObserver -> {
System.out.println("kota: getImageLiveDataが取得:" + gameJsonObserver);
System.out.println("kota: getImageLiveDataが取得:" + gameJsonObserver.getDrawingList());
System.out.println("kota: getImageLiveDataが取得:" + gameJsonObserver.getColorList());
System.out.println("kota: getImageLiveDataが取得:" + gameJsonObserver.getMap());
setupWithViewModel();
}
);
// Openされた画像ををObserveして、Viewに反映
gameViewModel.getOpenLiveData().observe (
getViewLifecycleOwner(),
openListObserver -> {
System.out.println("kota: オープンされた。オープンの配列:" + openListObserver);
setOpen(openListObserver);
}
);
// 疑われた画像ををObserveして、Viewに反映
gameViewModel.getQLiveData().observe (
getViewLifecycleOwner(),
QObserver -> {
System.out.println("kota: 疑われた。 疑われた配列: " + QObserver);
setQ(QObserver);
}
);
gameViewModel.getEndStateLiveData().observe (
getViewLifecycleOwner(),
endStateObserver -> {
System.out.println("kota:getEndState" + endStateObserver);
if(endStateObserver == 0) {
System.out.println("kota: 黒めくってゲームが終了!!:" + endStateObserver);
finishGameAlertMake(myTeam, nowTurn);
} else {
finishFullOpenGameAlertMake(myTeam, nowTurn);
}
}
);
gameViewModel.getTurnsLiveData().observe (
getViewLifecycleOwner(),
turnsObserver -> {
System.out.println("kota: ターンが変更。今のターン:" + turnsObserver);
nowTurn = turnsObserver;
}
);
gameViewModel.getTurnStateLiveData().observe (
getViewLifecycleOwner(),
turnStateObserver -> {
System.out.println("kota: turnStateが変更。0ならヒント入力中。1ならめくれるよ。:" + turnStateObserver);
turnState = turnStateObserver;
}
);
System.out.println("コンストラクタでのログ確認");
System.out.println("kota: isMasterかどうか:" + isMaster);
System.out.println("kota: getrid:" + iris.getRid());
System.out.println("kota: getteame:" + iris.getTeam());
System.out.println("kota: nowTurn:" + nowTurn);
System.out.println("kota: getMemberList:" + iris.getMemberList());
System.out.println("kota: getNickName:" + iris.getNickname());
System.out.println("kota: getImageLiveData:" + gameViewModel.getImageLiveData().getValue());
return view;
}
public void onClick(View v) {
for(int i=0; i< imageButtons.length; i++) {
if(v.getId() == imageButtons[i].getId()) {
System.out.println( "kota: タップされたボタンの配列番号:" + i);
System.out.println( "kota: nowTurn:" + nowTurn);
System.out.println( "kota: myTeam:" + myTeam);
System.out.println( "kota: isMaster:" + isMaster);
System.out.println( "kota: turnState:" + turnState);
// カードめくれなくする処理
if(nowTurn.equals(myTeam) && isMaster == false && turnState == 1) {
System.out.println( "kota: めくれる処理が呼ばれた:");
confirmAlertMake(i);
}
}
}
}
public boolean onLongTap(View v) {
for(int i=0; i< imageButtons.length; i++) {
if(v.getId() == imageButtons[i].getId()) {
System.out.println( "kota: ロングタップされたボタンの配列番号:" + i);
// 自分のターンのとき、疑い機能のあるアラート表示
// 相手のターンのとき、画像だけ確認できるアラート表示
if(nowTurn.equals(myTeam)) {
doubtAlertMake(i);
} else {
lookImageAlertMake(i);
}
}
// めくられた画像を長押でも確認できるようにする
if(v.getId() == backColors[i].getId()) {
System.out.println( "kota: タップされたボタンの配列番号:" + i);
lookImageAlertMake(i);
}
}
return false;
}
private void setupWithViewModel() {
System.out.println("kota: setupWithViewModel呼ばれた");
Iris iris = (Iris) this.getActivity().getApplication();
myTeam = iris.getTeam();
rid = iris.getRid();
isMaster = iris.isMaster();
System.out.println("kota: isMasterですかどうか:" + isMaster);
System.out.println(iris.getRid());
System.out.println(iris.getTeam());
System.out.println(iris.getMemberList());
System.out.println(iris.getNickname());
drawingList = gameViewModel.getGame().getDrawingList();
map = gameViewModel.getGame().getMap();
colorList = gameViewModel.getGame().getColorList();
Context context = getContext();
for (Integer i: map) {
// タップとロングタップのセット
imageButtons[i].setOnClickListener(this::onClick);
imageButtons[i].setOnLongClickListener(this::onLongTap);
backColors[i].setOnLongClickListener(this::onLongTap);
// 画像のセット
String urlSt = drawingList.get(map.get(i)).getDrawing();
System.out.println(i+urlSt);
setImage(i, urlSt, context);
// 初回だけセットする外枠の、メンバーとマスターで表示分け
// メンバー:全て肌色、マスター:赤・青・黒・グレーの表示
if(isMaster == true) {
if (colorList.get(i).contains("r")) {
backColors[i].setBackground(resources.getDrawable(R.drawable.red_image));
} else if (colorList.get(i).contains("b")) {
backColors[i].setBackground(resources.getDrawable(R.drawable.blue_image));
} else if (colorList.get(i).contains("g")) {
backColors[i].setBackground(resources.getDrawable(R.drawable.gray_image));
} else if (colorList.get(i).contains("d")) {
backColors[i].setBackground(resources.getDrawable(R.drawable.black_image));
}
} else {
backColors[i].setBackground(resources.getDrawable(R.drawable.skin_image));
}
}
}
/**
* URLから画像を取得
* Androidのルール的にメインスレッドで書くとクラッシュする
* 非同期で書かなければならない
**/
private void setImage(int cno, String urlSt, Context context) {
System.out.println("kota: setImage呼ばれた");
// Singleの別スレッドを立ち上げる
Executors.newSingleThreadExecutor().execute(() -> {
try {
// TODO: Drawingのsetが使われるまで、無理やり指定。
URL url = new URL(urlSt);
System.out.println("kota: 表示させるURL文字列 " + url);
// String urlString = "http://nitta-lab-www.is.konan-u.ac.jp/irisdata/image/" + rid + "-" + cno + ".png";
//URL url = new URL(urlString);
HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();
// タイムアウト設定
urlCon.setReadTimeout(10000);
urlCon.setConnectTimeout(20000);
// リクエストメソッド
urlCon.setRequestMethod("GET");
// リダイレクトを自動で許可しない設定
urlCon.setInstanceFollowRedirects(false);
InputStream is = urlCon.getInputStream();
Bitmap originalBMP = BitmapFactory.decodeStream(is);
Bitmap resizedMiniBMP = resize(originalBMP, (int) convertDp2Px(105, context),(int) convertDp2Px(60, context));
Bitmap resizedBigBMP = resize(originalBMP, (int) convertDp2Px(420, context),(int) convertDp2Px(240, context));
bmImages.put(cno, resizedBigBMP);
HandlerCompat.createAsync(getMainLooper()).post(() ->
// Mainスレッドに返す
imageButtons[cno].setImageBitmap(resizedMiniBMP)
);
} catch (IOException e) {
e.printStackTrace();
}
});
}
/**
* dpとpxを変換
* BitMapでImageを描画するためにどうしても必要だった
**/
private static float convertDp2Px(float dp, Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return dp * metrics.density;
}
/**
* 表示させる画像のサイズ調整
**/
private static Bitmap resize(Bitmap image, int maxWidth, int maxHeight) {
if (maxHeight > 0 && maxWidth > 0) {
int width = image.getWidth();
int height = image.getHeight();
float ratioBitmap = (float) width / (float) height;
float ratioMax = (float) maxWidth / (float) maxHeight;
int finalWidth = maxWidth;
int finalHeight = maxHeight;
if (ratioMax > 1) {
finalWidth = (int) ((float)maxHeight * ratioBitmap);
} else {
finalHeight = (int) ((float)maxWidth / ratioBitmap);
}
image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
return image;
} else {
return image;
}
}
/**
* 開けられたImageをViewに反映させる
* Observeして変更加わった度に呼ばれる
**/
private void setOpen(List<Boolean> openList) {
OpenRedCard = 0;
OpenBlueCard = 0;
for(int i=0; i< openList.size(); i++) {
if (openList.get(i) == true && nowOpenList.get(i) == false) {
// オープンだったときの描画
if (colorList.get(i).contains("r")) {
backColors[i].setBackground(resources.getDrawable(R.drawable.red_image));
imageButtons[i].setVisibility(INVISIBLE);
OpenRedCard += 1;
// if( !colorList.get(i).equals(myTeam) ){
// gameViewModel.addTurns();
// }
} else if (colorList.get(i).contains("b")) {
backColors[i].setBackground(resources.getDrawable(R.drawable.blue_image));
imageButtons[i].setVisibility(INVISIBLE);
OpenBlueCard += 1;
// if( !colorList.get(i).equals(myTeam) ){
// gameViewModel.addTurns();
// }
} else if (colorList.get(i).contains("g")) {
backColors[i].setBackground(resources.getDrawable(R.drawable.gray_image));
imageButtons[i].setVisibility(INVISIBLE);
// gameViewModel.addTurns();
} else if (colorList.get(i).contains("d")) {
backColors[i].setBackground(resources.getDrawable(R.drawable.black_image));
imageButtons[i].setVisibility(INVISIBLE);
gameViewModel.sendEndState();
finishGameAlertMake(myTeam, nowTurn);
}
setAnime(i);
nowOpenList.set(i, true);
} else if( openList.get(i) == true && colorList.get(i).contains("r") ){
OpenRedCard += 1;
} else if( openList.get(i) == true && colorList.get(i).contains("b") ){
OpenBlueCard += 1;
}
}
if( OpenRedCard == 6 ){
gameViewModel.sendEndState();
finishFullOpenGameAlertMake(myTeam, "r");
}else if( OpenBlueCard == 5 ){
gameViewModel.sendEndState();
finishFullOpenGameAlertMake(myTeam, "b");
}
}
//-----------------------------------------------------------------------------
// アラート関係の関数
/**
* 本当に裏返してよいか確認させるアラート
*/
private void confirmAlertMake(int cno){
String strTitle = "注意";
String strMessage = "本当にカードをめくってよろしいですか?";
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(getContext());
builder.setMessage(strMessage);
builder.setTitle(strTitle);
builder.setPositiveButton("ok", (dialog, id) -> setOpenRealTime(cno, true));
builder.setNegativeButton("キャンセル", (dialog, id) -> setOpenRealTime(cno, false));
builder.create();
builder.show();
}
/**
* アラートから呼ばれる、裏返す通信処理
**/
private void setOpenRealTime(int cno, boolean isOK) {
if(isOK == true) {
nowQList.set(cno, false);//疑い関係
gameViewModel.sendOpenList(cno);
if( colorList.get(cno).contains("d") ){
//Game終了
gameViewModel.sendEndState();
} else if ( !colorList.get(cno).contains(myTeam)){
gameViewModel.addTurns();
}
//赤のカードが何枚めくれているか(6枚めくれていたら勝利)
if( colorList.get(cno).equals("r") ){
OpenRedCard = 0;
nowOpenList.set(cno, true);
for( int i = 0; i < 16; i++ ){
if( colorList.get(i).equals("r") && nowOpenList.get(i).equals(true) ){
OpenRedCard += 1;
}
}
nowOpenList.set(cno, false);
if( OpenRedCard == 6 ){
gameViewModel.sendEndState();
finishFullOpenGameAlertMake(myTeam, "r");
}
}
//青のカードが何枚めくれているか(5枚めくれていたら勝利)
if( colorList.get(cno).equals("b") ){
OpenBlueCard = 0;
nowOpenList.set(cno, true);
for( int i = 0; i < 16; i++ ){
if( colorList.get(i).equals("b") && nowOpenList.get(i).equals(true) ){
OpenBlueCard += 1;
}
}
nowOpenList.set(cno, false);
if( OpenBlueCard == 5 ){
gameViewModel.sendEndState();
finishFullOpenGameAlertMake(myTeam, "b");
}
}
}
}
/**
* 自分のターンのときに、
* 疑うか疑わないかのアラートを表示させるコード
*/
private void doubtAlertMake(int cno){
String strTitle = "疑いますか?";
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(getContext());
builder.setTitle(strTitle);
ImageView iv = new ImageView(getContext());
iv.setImageBitmap(bmImages.get(cno));
iv.setAdjustViewBounds(true);
builder.setView(iv);
builder.setNegativeButton("疑わない", (dialog, id) -> setDoubt(cno, false));
builder.setPositiveButton("疑う", (dialog, id) -> setDoubt(cno, true));
builder.setNeutralButton("閉じる", (dialog, id) -> setNone(cno, true));
builder.create();
builder.show();
}
/**
* アラートから呼ばれる、疑いをかける処理
**/
private void setDoubt(int cno, boolean isOK) {
// 疑う処理
if( nowQList.get(cno) == false && isOK == true ){
gameViewModel.sendQ(cno);
} else if( nowQList.get(cno) == true && isOK == false ){
gameViewModel.sendQ(cno);
}
}
//疑われたら枠の色をチームの色に変更(諜報員のみ)
private void setQ(List<Boolean> QList) {
for(int i = 0; i < QList.size(); i++) {
if ( QList.get(i) == true && nowQList.get(i) == false && isMaster.equals(false) ) {
if( nowTurn.equals("r") ){
backColors[i].setBackground(resources.getDrawable(R.drawable.red_image));
} else {
backColors[i].setBackground(resources.getDrawable(R.drawable.blue_image));
}
nowQList.set(i, true);
} else if ( QList.get(i) == false && nowQList.get(i) == true && isMaster.equals(false)){
backColors[i].setBackground(resources.getDrawable(R.drawable.skin_image));
nowQList.set(i, false);
}
}
}
/**
* 相手のターンのときに、
* 画像だけ確認できるアラートを表示させるコード
*/
private void lookImageAlertMake(int cno){
String strTitle = "";
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(getContext());
builder.setTitle(strTitle);
ImageView iv = new ImageView(getContext());
iv.setImageBitmap(bmImages.get(cno));
iv.setAdjustViewBounds(true);
builder.setView(iv);
builder.setPositiveButton("完了", (dialog, id) -> setNone(cno, true));
builder.create();
builder.show();
}
/**
* アラートからOKを呼ばれたときにする処理
* まだ空
**/
private void setNone(int cno, boolean isOK) {
}
private void setAnime(int cno){
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
// animation時間 msec
scaleAnimation.setDuration(2000);
RotateAnimation rotate = new RotateAnimation(0.0f, 120.0f,
Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.5f);
// animation時間 msec
rotate.setDuration(2000);
AnimationSet animationSet = new AnimationSet( true );
// animationSetにそれぞれ追加する
animationSet.addAnimation( scaleAnimation );
animationSet.addAnimation( rotate );
imageButtons[cno].startAnimation(animationSet);
}
/**
* 黒いカードがひかれて、ゲームが終わったときに呼ばれるアラート
*/
private void finishGameAlertMake(String myTeam, String nowTurn) {
String strTitle;
String strMessage;
System.out.println("ゲームが終わった時のmyTeam:" + myTeam);
System.out.println("ゲームが終わった時のmyTurn:" + nowTurn);
if (myTeam.equals(nowTurn)) {
strTitle = "Your Lose...";
strMessage = "お疲れ様でした。\n残念ながら、あなたチームは負けました...";
} else {
strTitle = "Your Win!!";
strMessage = "お疲れ様でした。\nおめでとうございます、あなたチームの勝利です!";
}
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(getContext());
builder.setTitle(strTitle);
builder.setMessage(strMessage);
builder.setPositiveButton("完了", (dialog, id) -> setFinish());
builder.create();
builder.show();
}
/**
* 赤顔のカードがすべてひかれて、ゲームが終わったときに呼ばれるアラート
*/
private void finishFullOpenGameAlertMake(String myTeam, String nowTurn) {
String strTitle;
String strMessage;
System.out.println("ゲームが終わった時のmyTeam:" + myTeam);
System.out.println("ゲームが終わった時のmyTurn:" + nowTurn);
if ( !myTeam.equals(nowTurn)) {
strTitle = "Your Lose...";
strMessage = "お疲れ様でした。\n残念ながら、あなたチームは負けました...";
} else {
strTitle = "Your Win!!";
strMessage = "お疲れ様でした。\nおめでとうございます、あなたチームの勝利です!";
}
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(getContext());
builder.setTitle(strTitle);
builder.setMessage(strMessage);
builder.setPositiveButton("完了", (dialog, id) -> setFinish());
builder.create();
builder.show();
}
// TODO: 未完成の関数
/**
* ゲームが終了したときに呼ばれる関数
* 画面をトップに戻る動作でも書く?
**/
private void setFinish() {
Intent intent = new Intent(this.getActivity().getApplication(), MainActivity.class);
startActivity(intent);
}
}