Java tutorial
/* * Copyright (C) 2016 Tobias Bielefeld * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If you want to contact me, send me an e-mail at tobias.bielefeld@gmail.com */ package de.tobiasbielefeld.solitaire.ui; import android.content.Intent; import android.content.res.Configuration; import android.preference.PreferenceManager; import android.support.v4.app.DialogFragment; import android.os.Bundle; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdView; import java.util.Locale; import de.tobiasbielefeld.solitaire.R; import de.tobiasbielefeld.solitaire.classes.Card; import de.tobiasbielefeld.solitaire.classes.CardAndStack; import de.tobiasbielefeld.solitaire.classes.CustomAppCompatActivity; import de.tobiasbielefeld.solitaire.classes.Stack; import de.tobiasbielefeld.solitaire.dialogs.RestartDialog; import de.tobiasbielefeld.solitaire.handler.LoadGameHandler; import de.tobiasbielefeld.solitaire.helper.Animate; import de.tobiasbielefeld.solitaire.helper.AutoComplete; import de.tobiasbielefeld.solitaire.helper.GameLogic; import de.tobiasbielefeld.solitaire.helper.Hint; import de.tobiasbielefeld.solitaire.helper.MovingCards; import de.tobiasbielefeld.solitaire.helper.RecordList; import de.tobiasbielefeld.solitaire.helper.Scores; import de.tobiasbielefeld.solitaire.helper.Timer; import de.tobiasbielefeld.solitaire.ui.settings.Settings; import static de.tobiasbielefeld.solitaire.SharedData.*; /* * This is like the main activity, handles game input, controls the timer, loads and saves everything */ public class GameManager extends CustomAppCompatActivity implements View.OnTouchListener { public boolean hasLoaded = false; //used to call save() in onPause() only if load() has been called before public Button buttonAutoComplete; //button for auto complete public TextView mainTextViewTime, mainTextViewScore, mainTextViewRedeals; //textViews for time, scores and re-deals public RelativeLayout layoutGame; //contains the game stacks and cards public Toast toast; //a delicious toast! public static int loadCounter = 0; //used to count how many times the onCreate method is called, so I can avoid loading the game multiple times public long doubleTapSpeed = 500; //time delta between two taps in miliseconds public Stack tappedStack = null; public long firstTapTime; //stores the time of first tapping on a card private AdView mAdView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_game_manager); mAdView = (AdView) findViewById(R.id.adView2); AdRequest adRequest = new AdRequest.Builder().build(); mAdView.loadAd(adRequest); // load stuff layoutGame = (RelativeLayout) findViewById(R.id.mainRelativeLayoutGame); mainTextViewTime = (TextView) findViewById(R.id.mainTextViewTime); mainTextViewScore = (TextView) findViewById(R.id.mainTextViewScore); mainTextViewRedeals = (TextView) findViewById(R.id.textViewRedeals); buttonAutoComplete = (Button) findViewById(R.id.buttonMainAutoComplete); //initialize my static helper stuff final GameManager gm = this; recordList = new RecordList(gm); movingCards = new MovingCards(); hint = new Hint(); scores = new Scores(gm); gameLogic = new GameLogic(gm); animate = new Animate(gm); autoComplete = new AutoComplete(gm); timer = new Timer(gm); currentGame = lg.loadClass(this, getIntent().getIntExtra("game", 1)); savedGameData = getSharedPreferences(lg.getSharedPrefName(), MODE_PRIVATE); if (savedSharedData == null) { savedSharedData = PreferenceManager.getDefaultSharedPreferences(this); } updateIcons(); //initialize cards and stacks for (int i = 0; i < stacks.length; i++) { stacks[i] = new Stack(i); stacks[i].view = new ImageView(this); stacks[i].view.setBackgroundResource(R.drawable.background_stack); layoutGame.addView(stacks[i].view); } for (int i = 0; i < cards.length; i++) { cards[i] = new Card(i); cards[i].view = new ImageView(this); cards[i].view.setId(i); cards[i].view.setOnTouchListener(this); layoutGame.addView(cards[i].view); } currentGame.addOnTouchListener(this); scores.output(); loadCounter++; //post, because i need the dimensions of layoutGame to set the cards and stacks layoutGame.post(new Runnable() { //post a runnable to set the dimensions of cards and stacks when the layout has loaded @Override public void run() { boolean isLandscape = getResources() .getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; currentGame.setStacks(layoutGame, isLandscape); //if left handed mode is true, mirror all stacks if (getSharedBoolean(getString(R.string.pref_key_left_handed_mode), false)) { for (Stack stack : stacks) stack.view.setX(layoutGame.getWidth() - stack.view.getX() - Card.width); if (currentGame.hasArrow()) { for (Stack stack : stacks) { if (stack.hasArrow() > 0) { if (stack.hasArrow() == 1) { stack.view.setBackgroundResource(R.drawable.arrow_right); } else { stack.view.setBackgroundResource(R.drawable.arrow_left); } } } } } //calculate the spacing for cards on a stack Stack.defaultSpacing = Card.width / 2; //setup how the cards on the stacks will be stacked (offset to the previous card) //there are 4 possible directions. By default, the tableau stacks are stacked down //all other stacks don't have a visible offset //use setDirections() in a game to change that if (currentGame.directions == null) { for (int i = 0; i <= currentGame.getLastTableauID(); i++) { stacks[i].setSpacingDirection(1); } } else { for (int i = 0; i < currentGame.directions.length; i++) { stacks[i].setSpacingDirection(currentGame.directions[i]); } } //if there are direction borders set (when cards should'nt overlap another stack) use it. //else set the layout height/widht as maximum if (currentGame.directionBorders != null) { for (int i = 0; i < currentGame.directionBorders.length; i++) { if (currentGame.directionBorders[i] != -1) //-1 means no border stacks[i].setSpacingMax(currentGame.directionBorders[i]); else stacks[i].setSpacingMax(layoutGame); } } else { for (Stack stack : stacks) { stack.setSpacingMax(layoutGame); } } //load the game loadCounter--; if (loadCounter < 1) { scores.load(); LoadGameHandler loadGameHandler = new LoadGameHandler(gm); loadGameHandler.sendEmptyMessageDelayed(0, 200); } } }); } @Override public void onPause() { super.onPause(); //ony save if the game has been loaded before if (hasLoaded) { timer.save(); gameLogic.save(); } } @Override public void onResume() { super.onResume(); timer.load(); loadBackgroundColor(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { DialogFragment restartDialog = new RestartDialog(); restartDialog.show(getSupportFragmentManager(), "restartDialog"); return true; } return super.onKeyDown(keyCode, event); } public boolean onTouch(View v, MotionEvent event) { /* * handle input like touching cards and stacks and moving cards around */ //if something important happens don't accept input if (stopConditions()) return true; //also don't do anything with a second touch point if (event.getPointerId(0) != 0) { if (movingCards.hasCards()) movingCards.returnToPos(); return true; } float X = event.getX() + v.getX(), Y = event.getY() + v.getY(); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (currentGame.hasMainStack() && currentGame.testIfMainStackTouched(X, Y)) { if (currentGame.hasLimitedRedeals() && currentGame.dealFromStack().isEmpty()) { if (currentGame.getRemainingNumberOfRedeals() == 0) return true; else currentGame.incrementRedealCounter(this); } currentGame.onMainStackTouch(); } else if (cards[v.getId()].isUp()) {//&& currentGame.addCardToMovementTest(cards[v.getId()])) { if (getSharedBoolean("pref_key_double_tap_enable", true)) { if (tappedStack != null && tappedStack == cards[v.getId()].getStack() && System.currentTimeMillis() - firstTapTime < doubleTapSpeed) { CardAndStack cardAndStack = null; if (getSharedBoolean("pref_key_double_tap_all_cards", true) && cards[v.getId()].getStack().getID() <= currentGame.getLastTableauID()) { cardAndStack = currentGame.doubleTap(cards[v.getId()].getStack()); } else if (currentGame.addCardToMovementTest(cards[v.getId()])) { cardAndStack = currentGame.doubleTap(cards[v.getId()]); } if (cardAndStack != null) { movingCards.add(cardAndStack.getCard(), event.getX(), event.getY()); movingCards.moveToDestination(cardAndStack.getStack()); tappedStack = null; return true; } } else { tappedStack = cards[v.getId()].getStack(); firstTapTime = System.currentTimeMillis(); } } if (currentGame.addCardToMovementTest(cards[v.getId()])) { movingCards.add(cards[v.getId()], event.getX(), event.getY()); } } } else if (event.getAction() == MotionEvent.ACTION_MOVE && movingCards.hasCards()) { movingCards.move(X, Y); } else if (event.getAction() == MotionEvent.ACTION_UP && movingCards.hasCards()) { for (Stack stack : stacks) { if (stack.isOnLocation(X, Y) && movingCards.first().getStack() != stack && movingCards.first().test(stack)) { movingCards.moveToDestination(stack); return true; } } //if they aren't placed, return them to their old places movingCards.returnToPos(); } return true; } public void menuClick(View view) { //if something important happens don't accept input /*if (view.getId()==R.id.mainButtonRestart) { showRestartDialog(); return; }*/ if (stopConditions()) return; //also return moving cards, to prevent bugs if (movingCards.hasCards()) movingCards.returnToPos(); switch (view.getId()) { case R.id.mainButtonScores: startActivity(new Intent(getApplicationContext(), HighScores.class)); //open high scores activity break; case R.id.mainButtonUndo: recordList.undo(); //undo last movement break; case R.id.mainButtonHint: hint.showHint(); //show a hint break; case R.id.mainButtonRestart: //show restart dialog showRestartDialog(); break; case R.id.mainButtonSettings: //open Settings activity startActivity(new Intent(getApplicationContext(), Settings.class)); break; case R.id.buttonMainAutoComplete: autoComplete.start(); //start auto complete break; } } private void loadBackgroundColor() { RelativeLayout layout_background = (RelativeLayout) findViewById(R.id.mainRelativeLayoutGame); if (layout_background != null) { switch (getSharedString(getString(R.string.pref_key_background_color), "2")) { case "1": layout_background.setBackgroundResource(R.drawable.background_color_blue); break; case "2": layout_background.setBackgroundResource(R.drawable.background_color_green); break; case "3": layout_background.setBackgroundResource(R.drawable.background_color_red); break; case "4": layout_background.setBackgroundResource(R.drawable.background_color_yellow); break; case "5": layout_background.setBackgroundResource(R.drawable.background_color_orange); break; case "6": layout_background.setBackgroundResource(R.drawable.background_color_purple); break; } } } private boolean stopConditions() { /* * returns if the player should't be able to do actions (while animating for example) */ return (autoComplete.isRunning() || animate.cardIsAnimating() || hint.isWorking()); } public void showToast(final String text) { final GameManager gm = this; runOnUiThread(new Runnable() { public void run() { if (toast == null) toast = Toast.makeText(gm, text, Toast.LENGTH_SHORT); else toast.setText(text); toast.show(); } }); } public void updateNumberOfRedeals() { mainTextViewRedeals .setText(String.format(Locale.getDefault(), "%d", currentGame.getRemainingNumberOfRedeals())); } public void showRestartDialog() { RestartDialog restartDialog = new RestartDialog(); restartDialog.show(getSupportFragmentManager(), "restartDialog"); } public void updateIcons() { ImageView scores, hint, menu, undo, settings; scores = (ImageView) findViewById(R.id.button_scores); hint = (ImageView) findViewById(R.id.button_hint); menu = (ImageView) findViewById(R.id.button_restart); undo = (ImageView) findViewById(R.id.button_undo); settings = (ImageView) findViewById(R.id.button_settings); switch (getSharedString(getString(R.string.pref_key_icon_theme), "Material")) { case "Material": scores.setImageResource(R.drawable.scores_material); hint.setImageResource(R.drawable.hint_material); menu.setImageResource(R.drawable.menu_material); undo.setImageResource(R.drawable.undo_material); settings.setImageResource(R.drawable.settings_material); break; case "Old": scores.setImageResource(R.drawable.scores_old); hint.setImageResource(R.drawable.hint_old); menu.setImageResource(R.drawable.menu_old); undo.setImageResource(R.drawable.undo_old); settings.setImageResource(R.drawable.settings_old); break; } } }