Newer
Older
IrisClient / app / src / main / java / org / ntlab / irisclient / DrawingCardFragment.java
Kota on 10 Nov 2022 21 KB fix: プリント分の追加
package org.ntlab.irisclient;
import static android.os.Looper.getMainLooper;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
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.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がヒント入力中
    // ロングタップで表示させるために必要。非同期で値が格納され、順番通りに保存されないから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;


    // コンストラクタ
    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);
            }
        };

        // 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);
                }
        );

        gameViewModel.getEndStateLiveData().observe (
                getViewLifecycleOwner(),
                endStateObserver -> {
                    System.out.println("kota: " + endStateObserver);
                    if(endStateObserver == 0) {
                        System.out.println("kota: ゲームが終了!!:" + endStateObserver);
                        finishGameAlertMake(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: 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 != myTeam || isMaster == true || turnState == 0) {
                    return;
                } else {
                    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 == 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();

        System.out.println("adfasfasdfsf"+drawingList);

        Context context = getContext();

        for (int i = 0; i < 16; i++) {

            // タップとロングタップのセット
            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) {

        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(View.INVISIBLE);
                } else if (colorList.get(i).contains("b")) {
                    backColors[i].setBackground(resources.getDrawable(R.drawable.blue_image));
                    imageButtons[i].setVisibility(View.INVISIBLE);
                } else if (colorList.get(i).contains("g")) {
                    backColors[i].setBackground(resources.getDrawable(R.drawable.gray_image));
                    imageButtons[i].setVisibility(View.INVISIBLE);
                } else if (colorList.get(i).contains("d")) {
                    backColors[i].setBackground(resources.getDrawable(R.drawable.black_image));
                    imageButtons[i].setVisibility(View.INVISIBLE);
                    gameViewModel.sendEndState();
                    //finishGameAlertMake(myTeam, nowTurn);
                }
                setAnime(i);
                nowOpenList.set(i, true);
            }
        }
    }

    //-----------------------------------------------------------------------------
    // アラート関係の関数
    /**
     * 本当に裏返してよいか確認させるアラート
     */
    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) {
            gameViewModel.sendOpenList(cno);
        }
    }

    /**
     * 自分のターンのときに、
     * 疑うか疑わないかのアラートを表示させるコード
     */
    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.setPositiveButton("疑う", (dialog, id) -> setDoubt(cno, true));
        builder.setNegativeButton("キャンセル", (dialog, id) -> setDoubt(cno, false));
        builder.create();
        builder.show();
    }

    /**
     * アラートから呼ばれる、疑いをかける処理
     **/
    private void setDoubt(int cno, boolean isOK) {
        // 疑う処理
        // 実はまだViewは書けてない
        gameViewModel.sendQ(cno);
    }

    /**
     * 相手のターンのときに、
     * 画像だけ確認できるアラートを表示させるコード
     */
    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 == 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);
    }

}