/*
* Copyright (C) 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.apps.santatracker.doodles.tilt;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Vibrator;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ToggleButton;
import com.google.android.apps.santatracker.doodles.R;
import com.google.android.apps.santatracker.doodles.shared.AndroidUtils;
import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite;
import com.google.android.apps.santatracker.doodles.shared.Camera;
import com.google.android.apps.santatracker.doodles.shared.CameraShake;
import com.google.android.apps.santatracker.doodles.shared.DoodleConfig;
import com.google.android.apps.santatracker.doodles.shared.EventBus;
import com.google.android.apps.santatracker.doodles.shared.EventBus.EventBusListener;
import com.google.android.apps.santatracker.doodles.shared.GameFragment;
import com.google.android.apps.santatracker.doodles.shared.GameType;
import com.google.android.apps.santatracker.doodles.shared.HistoryManager;
import com.google.android.apps.santatracker.doodles.shared.HistoryManager.HistoryListener;
import com.google.android.apps.santatracker.doodles.shared.PineappleLogger;
import com.google.android.apps.santatracker.doodles.shared.RectangularInstructionActor;
import com.google.android.apps.santatracker.doodles.shared.SpriteActor;
import com.google.android.apps.santatracker.doodles.shared.Sprites;
import com.google.android.apps.santatracker.doodles.shared.UIUtil;
import com.google.android.apps.santatracker.doodles.shared.Vector2D;
import com.google.android.apps.santatracker.doodles.shared.sound.SoundManager;
import com.google.android.apps.santatracker.doodles.tilt.SwimmingModel.SwimmingState;
import com.google.android.apps.santatracker.util.MeasurementManager;
import com.google.firebase.analytics.FirebaseAnalytics;
import java.io.File;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import static com.google.android.apps.santatracker.doodles.shared.PineappleLogEvent.SWIMMING_GAME_TYPE;
/**
* The main fragment for the swimming game.
*/
public class SwimmingFragment extends GameFragment
implements SensorEventListener, EventBusListener {
private static final String TAG = SwimmingFragment.class.getSimpleName();
public static final String CURRENT_LEVEL_KEY = "CURRENT_LEVEL";
private static final float ACCELEROMETER_SCALE = 1.5f / 9.8f; // Scale to range -1.5:1.5.
private static final int END_VIEW_ON_DEATH_DELAY_MS = 1400;
public static boolean editorMode = false;
private SwimmingView swimmingView;
private DiveView diveView;
private TextView countdownView;
private Button saveButton;
private Button loadButton;
private Button resetButton;
private Button deleteButton;
private ToggleButton collisionModeButton;
private SwimmingModel model;
private SwimmingLevelManager levelManager;
private SensorManager sensorManager;
private Sensor accelerometerSensor;
private int displayRotation;
private int playCount = 0;
private long titleDurationMs = GameFragment.TITLE_DURATION_MS;
private SwimmingModel tempLevel;
private boolean mIsGameOver = false;
public SwimmingFragment() {
super();
}
public SwimmingFragment(Context context, DoodleConfig doodleConfig, PineappleLogger logger,
boolean editorMode) {
super(context, doodleConfig, logger);
SwimmingFragment.editorMode = editorMode;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (context == null) {
return null;
}
levelManager = new SwimmingLevelManager(context);
wrapper = new FrameLayout(context);
titleView = getTitleView(R.drawable.penguin_swim_loadingscreen, R.string.swimming);
wrapper.addView(titleView);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
loadGame();
}
});
return wrapper;
}
@Override
protected void firstPassLoadOnUiThread() {
final FrameLayout.LayoutParams wrapperLP =
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
final SwimmingFragment that = this;
scoreView = getScoreView();
pauseView = getPauseView();
int diveViewBottomMargin = (int) context.getResources().getDimension(
R.dimen.dive_margin_bottom);
int diveViewStartMargin = (int) context.getResources().getDimension(
R.dimen.dive_margin_left);
int diveViewSize = (int) context.getResources().getDimension(
R.dimen.dive_image_size);
FrameLayout.LayoutParams diveViewLP = new LayoutParams(diveViewSize, diveViewSize);
diveViewLP.setMargins(diveViewStartMargin, 0, 0, diveViewBottomMargin);
diveViewLP.gravity = Gravity.BOTTOM | Gravity.LEFT;
if (VERSION.SDK_INT >= 17) {
diveViewLP.setMarginStart(diveViewStartMargin);
}
diveView = new DiveView(context);
countdownView = new TextView(context);
countdownView.setGravity(Gravity.CENTER);
countdownView.setTextColor(context.getResources().getColor(R.color.ui_text_yellow));
countdownView.setTypeface(Typeface.DEFAULT_BOLD);
countdownView.setText("0");
countdownView.setVisibility(View.INVISIBLE);
Locale locale = context.getResources().getConfiguration().locale;
countdownView.setText(NumberFormat.getInstance(locale).format(3));
Point screenDimens = AndroidUtils.getScreenSize();
UIUtil.fitToBounds(countdownView, screenDimens.x / 10, screenDimens.y / 10);
LinearLayout gameView = new LinearLayout(context);
gameView.setOrientation(LinearLayout.VERTICAL);
// Add game view.
swimmingView = new SwimmingView(context);
LinearLayout.LayoutParams lp =
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
7);
gameView.addView(swimmingView, lp);
if (editorMode) {
LinearLayout buttonWrapper = new LinearLayout(context);
buttonWrapper.setOrientation(LinearLayout.HORIZONTAL);
lp =
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
1);
gameView.addView(buttonWrapper, lp);
resetButton =
getButton(
R.string.reset_level,
new OnClickListener() {
@Override
public void onClick(View v) {
SwimmingModel level = levelManager.loadDefaultLevel();
initializeLevel(level, false);
getActivity().getSharedPreferences(
context.getString(R.string.swimming), Context.MODE_PRIVATE)
.edit()
.putString(CURRENT_LEVEL_KEY, null)
.commit();
}
});
deleteButton =
getButton(
R.string.delete_levels,
new OnClickListener() {
@Override
public void onClick(View v) {
DialogFragment dialogFragment = new DeleteLevelDialogFragment();
dialogFragment.show(getActivity().getFragmentManager(), "delete");
}
});
loadButton =
getButton(
R.string.load_level,
new OnClickListener() {
@Override
public void onClick(View v) {
DialogFragment dialogFragment = new LoadLevelDialogFragment(that);
dialogFragment.show(getActivity().getFragmentManager(), "load");
}
});
saveButton =
getButton(
R.string.save_level,
new OnClickListener() {
@Override
public void onClick(View v) {
DialogFragment dialogFragment = new SaveLevelDialogFragment(that);
dialogFragment.show(getActivity().getFragmentManager(), "save");
}
});
collisionModeButton = new ToggleButton(context);
collisionModeButton.setText(R.string.scenery_mode);
collisionModeButton.setTextOff(context.getString(R.string.scenery_mode));
collisionModeButton.setTextOn(context.getString(R.string.collision_mode));
collisionModeButton.setOnCheckedChangeListener(
new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
model.collisionMode = isChecked;
}
});
lp =
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT,
1);
buttonWrapper.addView(deleteButton, lp);
buttonWrapper.addView(resetButton, lp);
buttonWrapper.addView(loadButton, lp);
buttonWrapper.addView(saveButton, lp);
buttonWrapper.addView(collisionModeButton, lp);
}
sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE);
accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (accelerometerSensor == null) {
// TODO: The game won't be playable without this, so what should we do?
Log.d(TAG, "Accelerometer sensor is null");
}
displayRotation = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getRotation();
wrapper.addView(gameView, 0, wrapperLP);
wrapper.addView(countdownView, 1);
wrapper.addView(diveView, 2, diveViewLP);
wrapper.addView(scoreView, 3);
wrapper.addView(pauseView, 4);
}
@Override
protected void secondPassLoadOnBackgroundThread() {
super.secondPassLoadOnBackgroundThread();
tempLevel = new SwimmingModel();
final SwimmingModel level = tempLevel;
historyManager = new HistoryManager(
context,
new HistoryListener() {
@Override
public void onFinishedLoading() {
addBestTimeLine(level);
}
@Override
public void onFinishedSaving() {}
});
initializeLevel(tempLevel, true);
}
@Override
protected void finalPassLoadOnUiThread() {
soundManager = SoundManager.getInstance();
loadSounds();
onFinishedLoading();
startHandlers();
tempLevel = null;
}
@Override
protected void replay() {
super.replay();
SwimmingModel level = new SwimmingModel();
initializeLevel(level, false);
}
@Override
protected void resume() {
super.resume();
if (uiRefreshHandler != null) {
sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
uiRefreshHandler.start(swimmingView);
}
}
@Override
public void onPause() {
super.onPause();
if (sensorManager != null) {
sensorManager.unregisterListener(this);
}
// Clear the path list because it's static and otherwise it hangs around forever.
if (SwimmingLevelChunk.pathList != null) {
SwimmingLevelChunk.pathList.clear();
}
}
@Override
protected void onDestroyHelper() {
if (swimmingView != null) {
swimmingView.setModel(null);
}
model = null;
tempLevel = null;
levelManager = null;
if (SwimmingLevelChunk.swimmingLevelChunks != null) {
SwimmingLevelChunk.swimmingLevelChunks.clear();
}
if (SwimmingLevelChunk.pathList != null) {
SwimmingLevelChunk.pathList.clear();
}
}
@Override
public void update(float deltaMs) {
if (isPaused) {
return;
}
model.update(deltaMs);
diveView.update(deltaMs);
// If we are in editor mode, hide the intro animation right away and skip the camera pan.
// Otherwise, wait until it has finished playing before fading and then run the camera pan.
if ((editorMode || model.timeElapsed >= titleDurationMs)
&& model.getState() == SwimmingState.INTRO) {
if (editorMode) {
Log.d(TAG, "Hiding intro animation right away.");
// Run on UI thread since background threads can't touch the intro view.
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
titleView.setVisibility(View.GONE);
}
});
model.setState(SwimmingState.WAITING);
} else {
Log.d(TAG, "Fading out and hiding intro animation.");
// Run on UI thread since background threads can't touch the intro view.
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
hideTitle();
}
});
model.setState(SwimmingState.WAITING);
}
}
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.values == null || model == null) {
return;
}
int sensorType = event.sensor.getType();
if (sensorType == Sensor.TYPE_ACCELEROMETER) {
float[] adjustedEventValues =
AndroidUtils.getAdjustedAccelerometerValues(displayRotation, event.values);
float x = -adjustedEventValues[0] * ACCELEROMETER_SCALE;
float y = -adjustedEventValues[1] * ACCELEROMETER_SCALE;
// Accelerometer input is very noisy, so we filter it using a (simple) low-pass filter.
float weight = 0.1f;
model.tilt.x = model.tilt.x + weight * (x - model.tilt.x);
model.tilt.y = model.tilt.y + weight * (y - model.tilt.y);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
@Override
public void onEventReceived(int type, final Object data) {
if (isDestroyed) {
return;
}
switch(type) {
case EventBus.SCORE_CHANGED:
int distance = integerValue(data);
boolean shouldAddStar = false;
if (model.currentScoreThreshold < SwimmingModel.SCORE_THRESHOLDS.length
&& distance >= SwimmingModel.SCORE_THRESHOLDS[model.currentScoreThreshold]) {
// Pop in star.
shouldAddStar = true;
model.currentScoreThreshold++;
}
updateScoreUi(distance, shouldAddStar);
break;
case EventBus.SWIMMING_DIVE:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
diveView.startCooldown();
}
});
break;
case EventBus.GAME_STATE_CHANGED:
SwimmingState state = (SwimmingState) data;
mIsGameOver = false;
if (state == SwimmingState.FINISHED) {
mIsGameOver = true;
calculateBestDistance();
calculateStars();
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
pauseView.hidePauseButton();
}
});
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (model == null) {
return;
}
int bestDistance = historyManager.getBestDistance(GameType.SWIMMING).intValue();
String collidedObjectType = model.swimmer.getCollidedObjectType();
scoreView.updateBestScore(
AndroidUtils.getText(
context.getResources(), R.string.swimming_score, bestDistance));
scoreView.setShareDrawable(
getShareImageDrawable(collidedObjectType));
diveView.hide();
scoreView.animateToEndState();
}
}, END_VIEW_ON_DEATH_DELAY_MS);
}
// [ANALYTICS]
FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(getActivity());
MeasurementManager.recordSwimmingEnd(analytics,
model.getStarCount(),
model.distanceMeters,
model.swimmer.getCollidedObjectType());
break;
case EventBus.PLAY_SOUND:
int resId = (int) data;
if (soundManager != null) {
soundManager.play(resId);
}
break;
case EventBus.MUTE_SOUNDS:
boolean shouldMute = (boolean) data;
if (soundManager != null) {
if (shouldMute) {
soundManager.mute();
} else {
soundManager.unmute();
}
}
break;
case EventBus.GAME_LOADED:
long loadTimeMs = (long) data;
titleDurationMs = Math.max(0, titleDurationMs - loadTimeMs);
Log.d(TAG, "Waiting " + titleDurationMs + "ms and then hiding title.");
break;
}
}
@Nullable
private Drawable getShareImageDrawable(String collidedObjectType) {
return ContextCompat.getDrawable(getActivity(), R.drawable.winner);
}
private void initializeLevel(final SwimmingModel newLevel, boolean shouldPlayIntro) {
EventBus.getInstance().clearListeners();
EventBus.getInstance().register(newLevel, EventBus.VIBRATE);
EventBus.getInstance().register(newLevel, EventBus.SHAKE_SCREEN);
EventBus.getInstance().register(newLevel, EventBus.GAME_STATE_CHANGED);
// Initialize Activity-specific stuff.
EventBus.getInstance().register(this);
Point size = AndroidUtils.getScreenSize();
newLevel.screenWidth = size.x;
newLevel.screenHeight = size.y;
newLevel.addActor(new Camera(newLevel.screenWidth, newLevel.screenHeight));
newLevel.addActor(new CameraShake());
// Center the level horizontally on the screen and scale to fit.
newLevel.camera.moveImmediatelyTo(
Vector2D.get(0, 0),
Vector2D.get(SwimmingModel.LEVEL_WIDTH, 0));
newLevel.playCount = playCount++;
newLevel.locale = getResources().getConfiguration().locale;
if (isDestroyed) {
return;
}
SwimmerActor swimmer = SwimmerActor.create(Vector2D.get(0, 0), context.getResources(),
this);
if (swimmer == null) {
return;
}
swimmer.moveTo(
SwimmingModel.LEVEL_WIDTH / 2 - swimmer.collisionBody.getWidth() / 2,
SwimmerActor.KICKOFF_IDLE_Y_OFFSET);
newLevel.addActor(swimmer);
DistanceMarkerActor startingBlock =
new DistanceMarkerActor(0, ColoredRectangleActor.STARTING_BLOCK, 1000);
newLevel.addActor(startingBlock);
SpriteActor banner = new SpriteActor(
AnimatedSprite.fromFrames(context.getResources(), Sprites.penguin_swim_banner),
Vector2D.get(SwimmingModel.LEVEL_WIDTH / 2, startingBlock.position.y), Vector2D.get());
banner.scale = 2;
banner.zIndex = 2;
banner.sprite.setAnchor(banner.sprite.frameWidth / 2, banner.sprite.frameHeight - 50);
newLevel.addActor(banner);
newLevel.addActor(new DistanceMarkerActor(30, ColoredRectangleActor.DISTANCE_30M));
newLevel.addActor(new DistanceMarkerActor(50, ColoredRectangleActor.DISTANCE_50M));
newLevel.addActor(new DistanceMarkerActor(100, ColoredRectangleActor.DISTANCE_100M));
newLevel.addActor(new DistanceMarkerActor(
SwimmingLevelChunk.LEVEL_LENGTH_IN_METERS, ColoredRectangleActor.DISTANCE_LEVEL_LENGTH));
if (historyManager != null) {
addBestTimeLine(newLevel);
}
if (isDestroyed) {
return;
}
ObstacleManager obstacleManager = new ObstacleManager(swimmer, context);
newLevel.addActor(obstacleManager);
newLevel.camera.position.y = -newLevel.camera.toWorldScale(newLevel.screenHeight);
newLevel.clampCameraPosition(); // Clamp camera so that it doesn't jump when we start swimming.
AnimatedSprite swimmingTutorialSprite =
AnimatedSprite.fromFrames(context.getResources(), Sprites.tutorial_swimming);
swimmingTutorialSprite.setFPS(6);
RectangularInstructionActor instructions = new RectangularInstructionActor(
context.getResources(), swimmingTutorialSprite);
instructions.hidden = true;
instructions.scale = (newLevel.screenWidth * 0.6f) / instructions.rectangle.frameWidth;
// Put instructions at top right, slightly below pause button.
instructions.position.set(newLevel.screenWidth / 2 - instructions.getScaledWidth() / 2, 70);
newLevel.addUiActor(instructions);
newLevel.setCountdownView(countdownView);
if (!shouldPlayIntro) {
// Skip State.INTRO.
newLevel.setState(SwimmingState.WAITING);
}
if (isDestroyed) {
return;
}
model = newLevel;
swimmingView.setModel(model);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
initializeLevelUiThread(newLevel);
}
});
// Hint that this would be a good time to do some garbage collection since we should be able
// to get rid of any stuff from the previous level at this time.
System.gc();
}
// Initialize level parts that need to happen in UI thread.
private void initializeLevelUiThread(final SwimmingModel newLevel) {
if (isDestroyed) {
return;
}
scoreView.updateCurrentScore(
AndroidUtils.getText(context.getResources(), R.string.swimming_score, 0), false);
pauseView.showPauseButton();
diveView.show();
newLevel.vibrator = (Vibrator) getActivity().getSystemService(Activity.VIBRATOR_SERVICE);
}
@Override
protected void loadSounds() {
super.loadSounds();
soundManager.loadShortSound(context, R.raw.swimming_dive_down);
soundManager.loadShortSound(context, R.raw.swimming_dive_up);
soundManager.loadShortSound(context, R.raw.swimming_ice_splash_a);
soundManager.loadShortSound(context, R.raw.swimming_duck_collide);
soundManager.loadShortSound(context, R.raw.swimming_ice_collide);
soundManager.loadShortSound(context, R.raw.swimming_grab);
}
private void addBestTimeLine(SwimmingModel level) {
Double bestDistance = historyManager.getBestDistance(GameType.SWIMMING);
if (bestDistance != null) {
level.addActor(new DistanceMarkerActor(bestDistance.intValue(),
ColoredRectangleActor.DISTANCE_PR));
}
}
private void calculateStars() {
Integer bestStarCount = historyManager.getBestStarCount(GameType.SWIMMING);
int modelStarCount = model.getStarCount();
if (bestStarCount == null || bestStarCount < modelStarCount) {
historyManager.setBestStarCount(GameType.SWIMMING, modelStarCount);
}
}
private void calculateBestDistance() {
Double bestDistance = historyManager.getBestDistance(GameType.SWIMMING);
if (bestDistance == null || bestDistance < model.distanceMeters) {
historyManager.setBestDistance(GameType.SWIMMING, model.distanceMeters);
}
}
private Button getButton(int textId, OnClickListener onClickListener) {
Button button = new Button(context);
button.setText(textId);
button.setOnClickListener(onClickListener);
return button;
}
private void updateScoreUi(final int score, final boolean shouldShowStars) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
scoreView.updateCurrentScore(
AndroidUtils.getText(context.getResources(), R.string.swimming_score, score),
shouldShowStars);
if (shouldShowStars) {
scoreView.addStar();
}
}
});
}
private int integerValue(Object object) {
if (object instanceof Integer) {
return (int) object;
} else {
throw new IllegalArgumentException("Unknown event data type");
}
}
@Override
public void onGamePause() {
if (model != null && model.swimmer != null) {
model.swimmer.controlsEnabled = false;
}
super.onGamePause();
}
@Override
protected void onGameResume() {
if (model != null && model.swimmer != null) {
model.swimmer.controlsEnabled = true;
}
super.onGameResume();
}
@Override
protected void onGameReplay() {
if (model != null && model.swimmer != null) {
model.swimmer.controlsEnabled = true;
}
super.onGameReplay();
}
@Override
protected boolean onTitleTapped() {
if (model != null && model.getState() == SwimmingState.INTRO) {
// If the user taps the screen while the intro animation is playing, end the intro
// immediately and transition into the game.
model.timeElapsed = GameFragment.TITLE_DURATION_MS;
return true;
}
return false;
}
@Override
protected String getGameType() {
return SWIMMING_GAME_TYPE;
}
@Override
protected float getScore() {
return model.distanceMeters;
}
@Override
protected int getShareImageId() {
String collidedObjectType = model.swimmer.getCollidedObjectType();
if (BoundingBoxSpriteActor.ICE_CUBE.equals(collidedObjectType)) {
return 0;
} else if (BoundingBoxSpriteActor.DUCK.equals(collidedObjectType)) {
return 1;
} else { // Octopus hand grab.
return 2;
}
}
/**
* A dialog fragment for loading a swimming level.
*/
public static class LoadLevelDialogFragment extends DialogFragment {
private SwimmingFragment swimmingFragment;
public LoadLevelDialogFragment(SwimmingFragment swimmingFragment) {
this.swimmingFragment = swimmingFragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String[] fileList =
SwimmingLevelManager.levelsDir.exists()
? SwimmingLevelManager.levelsDir.list()
: new String[0];
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder
.setTitle(R.string.load_level)
.setItems(
fileList,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SwimmingModel level = swimmingFragment.levelManager.loadLevel(fileList[which]);
swimmingFragment.initializeLevel(level, false);
// Save the current level so we automatically come back to it later.
getActivity()
.getSharedPreferences(
swimmingFragment.context.getString(R.string.swimming),
Context.MODE_PRIVATE)
.edit()
.putString(CURRENT_LEVEL_KEY, fileList[which])
.commit();
}
});
return builder.create();
}
}
/**
* A dialog fragment for saving a swimming level.
*/
public static class SaveLevelDialogFragment extends DialogFragment {
private SwimmingFragment swimmingFragment;
public SaveLevelDialogFragment(SwimmingFragment swimmingFragment) {
this.swimmingFragment = swimmingFragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final EditText editText = new EditText(swimmingFragment.context);
editText.setText(swimmingFragment.model.levelName);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder
.setTitle(R.string.save_level)
.setView(editText)
.setPositiveButton(
R.string.save,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
swimmingFragment.levelManager.saveLevel(
swimmingFragment.model, editText.getText().toString());
}
})
.setNegativeButton(
R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
// Do nothing.
}
});
return builder.create();
}
}
/**
* A dialog fragment for deleting a swimming level.
*/
public static class DeleteLevelDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final List<Integer> selectedItems = new ArrayList<>();
final String[] fileList =
SwimmingLevelManager.levelsDir.exists()
? SwimmingLevelManager.levelsDir.list()
: new String[0];
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder
.setTitle(R.string.delete_levels)
.setMultiChoiceItems(
fileList,
null,
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (isChecked) {
selectedItems.add(which);
} else if (selectedItems.contains(which)) {
selectedItems.remove(Integer.valueOf(which));
}
}
})
.setPositiveButton(
R.string.delete,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
for (Integer selection : selectedItems) {
File file = new File(SwimmingLevelManager.levelsDir, fileList[selection]);
file.delete();
}
}
})
.setNegativeButton(
R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
// Do nothing.
}
});
return builder.create();
}
}
public boolean isGameOver() {
return mIsGameOver;
}
}