Compare commits

...

5 commits

9 changed files with 657 additions and 63 deletions

View file

@ -28,7 +28,12 @@
<activity <activity
android:name=".HighScoresActivity" android:name=".HighScoresActivity"
android:theme="@style/Theme.AppCompat.NoActionBar" android:exported="false"
android:exported="false" /> android:theme="@style/Theme.AppCompat.NoActionBar" />
<activity
android:name=".StatsActivity"
android:exported="false"
android:theme="@style/Theme.AppCompat.NoActionBar" />
</application> </application>
</manifest> </manifest>

View file

@ -21,6 +21,9 @@ import com.mintris.model.GameBoard
import com.mintris.audio.GameMusic import com.mintris.audio.GameMusic
import com.mintris.model.HighScoreManager import com.mintris.model.HighScoreManager
import android.content.Intent import android.content.Intent
import com.mintris.model.StatsManager
import java.text.SimpleDateFormat
import java.util.*
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@ -32,6 +35,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var gameMusic: GameMusic private lateinit var gameMusic: GameMusic
private lateinit var titleScreen: TitleScreen private lateinit var titleScreen: TitleScreen
private lateinit var highScoreManager: HighScoreManager private lateinit var highScoreManager: HighScoreManager
private lateinit var statsManager: StatsManager
// Game state // Game state
private var isSoundEnabled = true private var isSoundEnabled = true
@ -40,6 +44,8 @@ class MainActivity : AppCompatActivity() {
private val maxLevel = 20 private val maxLevel = 20
private var currentScore = 0 private var currentScore = 0
private var currentLevel = 1 private var currentLevel = 1
private var gameStartTime: Long = 0
private var piecesPlaced: Int = 0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -53,6 +59,7 @@ class MainActivity : AppCompatActivity() {
titleScreen = binding.titleScreen titleScreen = binding.titleScreen
gameMusic = GameMusic(this) gameMusic = GameMusic(this)
highScoreManager = HighScoreManager(this) highScoreManager = HighScoreManager(this)
statsManager = StatsManager(this)
// Set up game view // Set up game view
gameView.setGameBoard(gameBoard) gameView.setGameBoard(gameBoard)
@ -117,6 +124,8 @@ class MainActivity : AppCompatActivity() {
} else { } else {
android.util.Log.d("MainActivity", "Sound is disabled, skipping haptic feedback") android.util.Log.d("MainActivity", "Sound is disabled, skipping haptic feedback")
} }
// Record line clear in stats
statsManager.recordLineClear(lineCount)
} }
// Add callbacks for piece movement and locking // Add callbacks for piece movement and locking
@ -130,6 +139,7 @@ class MainActivity : AppCompatActivity() {
if (isSoundEnabled) { if (isSoundEnabled) {
gameHaptics.vibrateForPieceLock() gameHaptics.vibrateForPieceLock()
} }
piecesPlaced++
} }
// Set up button click listeners with haptic feedback // Set up button click listeners with haptic feedback
@ -187,6 +197,13 @@ class MainActivity : AppCompatActivity() {
} }
} }
// Set up stats button
binding.statsButton.setOnClickListener {
gameHaptics.performHapticFeedback(it, HapticFeedbackConstants.VIRTUAL_KEY)
val intent = Intent(this, StatsActivity::class.java)
startActivity(intent)
}
// Initialize level selector // Initialize level selector
updateLevelSelector() updateLevelSelector()
@ -205,6 +222,9 @@ class MainActivity : AppCompatActivity() {
binding.linesText.text = lines.toString() binding.linesText.text = lines.toString()
binding.comboText.text = gameBoard.getCombo().toString() binding.comboText.text = gameBoard.getCombo().toString()
// Update current level for stats
currentLevel = level
// Force redraw of next piece preview // Force redraw of next piece preview
binding.nextPieceView.invalidate() binding.nextPieceView.invalidate()
} }
@ -213,7 +233,35 @@ class MainActivity : AppCompatActivity() {
* Show game over screen * Show game over screen
*/ */
private fun showGameOver(score: Int) { private fun showGameOver(score: Int) {
binding.finalScoreText.text = getString(R.string.score) + ": " + score val gameTime = System.currentTimeMillis() - gameStartTime
// Update session stats
statsManager.updateSessionStats(
score = score,
lines = gameBoard.lines,
pieces = piecesPlaced,
time = gameTime,
level = currentLevel
)
// End session and save stats
statsManager.endSession()
// Update session stats display
val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
timeFormat.timeZone = TimeZone.getTimeZone("UTC")
binding.sessionScoreText.text = getString(R.string.session_score, score)
binding.sessionLinesText.text = getString(R.string.session_lines, gameBoard.lines)
binding.sessionPiecesText.text = getString(R.string.session_pieces, piecesPlaced)
binding.sessionTimeText.text = getString(R.string.session_time, timeFormat.format(gameTime))
binding.sessionLevelText.text = getString(R.string.session_level, currentLevel)
// Update session line clear stats
binding.sessionSinglesText.text = getString(R.string.singles, statsManager.getSessionSingles())
binding.sessionDoublesText.text = getString(R.string.doubles, statsManager.getSessionDoubles())
binding.sessionTriplesText.text = getString(R.string.triples, statsManager.getSessionTriples())
binding.sessionTetrisesText.text = getString(R.string.tetrises, statsManager.getSessionTetrises())
// Check if this is a high score // Check if this is a high score
if (highScoreManager.isHighScore(score)) { if (highScoreManager.isHighScore(score)) {
@ -291,10 +339,13 @@ class MainActivity : AppCompatActivity() {
private fun startGame() { private fun startGame() {
gameView.start() gameView.start()
gameMusic.setEnabled(isMusicEnabled) // Explicitly set enabled state gameMusic.setEnabled(isMusicEnabled)
if (isMusicEnabled) { if (isMusicEnabled) {
gameMusic.start() gameMusic.start()
} }
gameStartTime = System.currentTimeMillis()
piecesPlaced = 0
statsManager.startNewSession()
} }
private fun restartGame() { private fun restartGame() {

View file

@ -0,0 +1,54 @@
package com.mintris
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.mintris.databinding.ActivityStatsBinding
import com.mintris.model.StatsManager
import java.text.SimpleDateFormat
import java.util.*
class StatsActivity : AppCompatActivity() {
private lateinit var binding: ActivityStatsBinding
private lateinit var statsManager: StatsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityStatsBinding.inflate(layoutInflater)
setContentView(binding.root)
statsManager = StatsManager(this)
// Set up back button
binding.backButton.setOnClickListener {
finish()
}
updateStats()
}
private fun updateStats() {
// Format time duration
val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
timeFormat.timeZone = TimeZone.getTimeZone("UTC")
// Update lifetime stats
binding.totalGamesText.text = getString(R.string.total_games, statsManager.getTotalGames())
binding.totalScoreText.text = getString(R.string.total_score, statsManager.getTotalScore())
binding.totalLinesText.text = getString(R.string.total_lines, statsManager.getTotalLines())
binding.totalPiecesText.text = getString(R.string.total_pieces, statsManager.getTotalPieces())
binding.totalTimeText.text = getString(R.string.total_time, timeFormat.format(statsManager.getTotalTime()))
// Update line clear stats
binding.totalSinglesText.text = getString(R.string.singles, statsManager.getTotalSingles())
binding.totalDoublesText.text = getString(R.string.doubles, statsManager.getTotalDoubles())
binding.totalTriplesText.text = getString(R.string.triples, statsManager.getTotalTriples())
binding.totalTetrisesText.text = getString(R.string.tetrises, statsManager.getTotalTetrises())
// Update best performance stats
binding.maxLevelText.text = getString(R.string.max_level, statsManager.getMaxLevel())
binding.maxScoreText.text = getString(R.string.max_score, statsManager.getMaxScore())
binding.maxLinesText.text = getString(R.string.max_lines, statsManager.getMaxLines())
}
}

View file

@ -12,6 +12,10 @@ import java.util.Random
import android.util.Log import android.util.Log
import com.mintris.model.HighScoreManager import com.mintris.model.HighScoreManager
import com.mintris.model.HighScore import com.mintris.model.HighScore
import kotlin.math.abs
import androidx.core.graphics.withTranslation
import androidx.core.graphics.withScale
import androidx.core.graphics.withRotation
class TitleScreen @JvmOverloads constructor( class TitleScreen @JvmOverloads constructor(
context: Context, context: Context,
@ -29,6 +33,14 @@ class TitleScreen @JvmOverloads constructor(
private var width = 0 private var width = 0
private var height = 0 private var height = 0
private val tetrominosToAdd = mutableListOf<Tetromino>() private val tetrominosToAdd = mutableListOf<Tetromino>()
private val highScoreManager = HighScoreManager(context) // Pre-allocate HighScoreManager
// Touch handling variables
private var startX = 0f
private var startY = 0f
private var lastTouchX = 0f
private var lastTouchY = 0f
private val maxTapMovement = 20f // Maximum movement allowed for a tap (in pixels)
// Callback for when the user touches the screen // Callback for when the user touches the screen
var onStartGame: (() -> Unit)? = null var onStartGame: (() -> Unit)? = null
@ -187,58 +199,31 @@ class TitleScreen @JvmOverloads constructor(
tetrominosToAdd.add(createRandomTetromino()) tetrominosToAdd.add(createRandomTetromino())
} else { } else {
try { try {
// Save canvas state before rotation
canvas.save()
// Translate to the tetromino's position
canvas.translate(tetromino.x, tetromino.y)
// Scale according to the tetromino's scale factor
canvas.scale(tetromino.scale, tetromino.scale)
// Rotate around the center of the tetromino
val centerX = tetromino.shape.size * cellSize / 2
val centerY = tetromino.shape.size * cellSize / 2
canvas.rotate(tetromino.rotation.toFloat(), centerX, centerY)
// Draw the tetromino // Draw the tetromino
for (row in tetromino.shape.indices) { for (y in 0 until tetromino.shape.size) {
for (col in 0 until tetromino.shape[row].size) { for (x in 0 until tetromino.shape.size) {
if (tetromino.shape[row][col] == 1) { if (tetromino.shape[y][x] == 1) {
// Draw larger glow effect val left = x * cellSize
glowPaint.alpha = 30 val top = y * cellSize
canvas.drawRect( val right = left + cellSize
col * cellSize - 8, val bottom = top + cellSize
row * cellSize - 8,
(col + 1) * cellSize + 8,
(row + 1) * cellSize + 8,
glowPaint
)
// Draw medium glow // Draw block with glow effect
glowPaint.alpha = 60 canvas.withTranslation(tetromino.x, tetromino.y) {
canvas.drawRect( withScale(tetromino.scale, tetromino.scale) {
col * cellSize - 4, withRotation(tetromino.rotation.toFloat(),
row * cellSize - 4, tetromino.shape.size * cellSize / 2,
(col + 1) * cellSize + 4, tetromino.shape.size * cellSize / 2) {
(row + 1) * cellSize + 4, // Draw glow
glowPaint canvas.drawRect(left - 8f, top - 8f, right + 8f, bottom + 8f, glowPaint)
) // Draw block
canvas.drawRect(left, top, right, bottom, paint)
// Draw main block }
canvas.drawRect( }
col * cellSize, }
row * cellSize,
(col + 1) * cellSize,
(row + 1) * cellSize,
paint
)
} }
} }
} }
// Restore canvas state
canvas.restore()
} catch (e: Exception) { } catch (e: Exception) {
Log.e("TitleScreen", "Error drawing tetromino", e) Log.e("TitleScreen", "Error drawing tetromino", e)
} }
@ -252,8 +237,7 @@ class TitleScreen @JvmOverloads constructor(
val titleY = height * 0.4f val titleY = height * 0.4f
canvas.drawText("mintris", width / 2f, titleY, titlePaint) canvas.drawText("mintris", width / 2f, titleY, titlePaint)
// Draw high scores // Draw high scores using pre-allocated manager
val highScoreManager = HighScoreManager(context)
val highScores: List<HighScore> = highScoreManager.getHighScores() val highScores: List<HighScore> = highScoreManager.getHighScores()
val highScoreY = height * 0.5f val highScoreY = height * 0.5f
if (highScores.isNotEmpty()) { if (highScores.isNotEmpty()) {
@ -274,10 +258,50 @@ class TitleScreen @JvmOverloads constructor(
} }
override fun onTouchEvent(event: MotionEvent): Boolean { override fun onTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_DOWN) { when (event.action) {
onStartGame?.invoke() MotionEvent.ACTION_DOWN -> {
startX = event.x
startY = event.y
lastTouchX = event.x
lastTouchY = event.y
return true return true
} }
MotionEvent.ACTION_MOVE -> {
val deltaX = event.x - lastTouchX
val deltaY = event.y - lastTouchY
// Update tetromino positions
for (tetromino in tetrominos) {
tetromino.x += deltaX * 0.5f
tetromino.y += deltaY * 0.5f
}
lastTouchX = event.x
lastTouchY = event.y
invalidate()
return true
}
MotionEvent.ACTION_UP -> {
val deltaX = event.x - startX
val deltaY = event.y - startY
// If the movement was minimal, treat as a tap
if (abs(deltaX) < maxTapMovement && abs(deltaY) < maxTapMovement) {
performClick()
}
return true
}
}
return super.onTouchEvent(event) return super.onTouchEvent(event)
} }
override fun performClick(): Boolean {
// Call the superclass's performClick
super.performClick()
// Handle the click event
onStartGame?.invoke()
return true
}
} }

View file

@ -31,6 +31,8 @@ class GameBoard(
var level = 1 var level = 1
var lines = 0 var lines = 0
var isGameOver = false var isGameOver = false
var isHardDropInProgress = false // Make public
var isPieceLocking = false // Make public
// Scoring state // Scoring state
private var combo = 0 private var combo = 0
@ -150,6 +152,9 @@ class GameBoard(
* Move the current piece down (soft drop) * Move the current piece down (soft drop)
*/ */
fun moveDown(): Boolean { fun moveDown(): Boolean {
// Don't allow movement if a hard drop is in progress or piece is locking
if (isHardDropInProgress || isPieceLocking) return false
return if (canMove(0, 1)) { return if (canMove(0, 1)) {
currentPiece?.y = currentPiece?.y?.plus(1) ?: 0 currentPiece?.y = currentPiece?.y?.plus(1) ?: 0
onPieceMove?.invoke() onPieceMove?.invoke()
@ -164,9 +169,19 @@ class GameBoard(
* Hard drop the current piece * Hard drop the current piece
*/ */
fun hardDrop() { fun hardDrop() {
while (moveDown()) { if (isHardDropInProgress || isPieceLocking) return // Prevent multiple hard drops
// Keep moving down until blocked
isHardDropInProgress = true
val piece = currentPiece ?: return
// Move piece down until it can't move anymore
while (canMove(0, 1)) {
piece.y++
onPieceMove?.invoke()
} }
// Lock the piece immediately
lockPiece()
} }
/** /**
@ -249,9 +264,12 @@ class GameBoard(
} }
/** /**
* Lock the current piece in place and check for completed lines * Lock the current piece in place
*/ */
fun lockPiece() { private fun lockPiece() {
if (isPieceLocking) return // Prevent recursive locking
isPieceLocking = true
val piece = currentPiece ?: return val piece = currentPiece ?: return
// Add the piece to the grid // Add the piece to the grid
@ -275,11 +293,15 @@ class GameBoard(
// Find and clear lines immediately // Find and clear lines immediately
findAndClearLines() findAndClearLines()
// Spawn new piece // Spawn new piece immediately
spawnPiece() spawnPiece()
// Allow holding piece again after locking // Allow holding piece again after locking
canHold = true canHold = true
// Reset both states after everything is done
isPieceLocking = false
isHardDropInProgress = false
} }
/** /**

View file

@ -0,0 +1,175 @@
package com.mintris.model
import android.content.Context
import android.content.SharedPreferences
class StatsManager(context: Context) {
private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
// Lifetime stats
private var totalGames: Int = 0
private var totalScore: Long = 0
private var totalLines: Int = 0
private var totalPieces: Int = 0
private var totalTime: Long = 0
private var maxLevel: Int = 0
private var maxScore: Int = 0
private var maxLines: Int = 0
// Line clear stats (lifetime)
private var totalSingles: Int = 0
private var totalDoubles: Int = 0
private var totalTriples: Int = 0
private var totalTetrises: Int = 0
// Session stats
private var sessionScore: Int = 0
private var sessionLines: Int = 0
private var sessionPieces: Int = 0
private var sessionTime: Long = 0
private var sessionLevel: Int = 0
// Line clear stats (session)
private var sessionSingles: Int = 0
private var sessionDoubles: Int = 0
private var sessionTriples: Int = 0
private var sessionTetrises: Int = 0
init {
loadStats()
}
private fun loadStats() {
totalGames = prefs.getInt(KEY_TOTAL_GAMES, 0)
totalScore = prefs.getLong(KEY_TOTAL_SCORE, 0)
totalLines = prefs.getInt(KEY_TOTAL_LINES, 0)
totalPieces = prefs.getInt(KEY_TOTAL_PIECES, 0)
totalTime = prefs.getLong(KEY_TOTAL_TIME, 0)
maxLevel = prefs.getInt(KEY_MAX_LEVEL, 0)
maxScore = prefs.getInt(KEY_MAX_SCORE, 0)
maxLines = prefs.getInt(KEY_MAX_LINES, 0)
// Load line clear stats
totalSingles = prefs.getInt(KEY_TOTAL_SINGLES, 0)
totalDoubles = prefs.getInt(KEY_TOTAL_DOUBLES, 0)
totalTriples = prefs.getInt(KEY_TOTAL_TRIPLES, 0)
totalTetrises = prefs.getInt(KEY_TOTAL_TETRISES, 0)
}
private fun saveStats() {
prefs.edit()
.putInt(KEY_TOTAL_GAMES, totalGames)
.putLong(KEY_TOTAL_SCORE, totalScore)
.putInt(KEY_TOTAL_LINES, totalLines)
.putInt(KEY_TOTAL_PIECES, totalPieces)
.putLong(KEY_TOTAL_TIME, totalTime)
.putInt(KEY_MAX_LEVEL, maxLevel)
.putInt(KEY_MAX_SCORE, maxScore)
.putInt(KEY_MAX_LINES, maxLines)
.putInt(KEY_TOTAL_SINGLES, totalSingles)
.putInt(KEY_TOTAL_DOUBLES, totalDoubles)
.putInt(KEY_TOTAL_TRIPLES, totalTriples)
.putInt(KEY_TOTAL_TETRISES, totalTetrises)
.apply()
}
fun startNewSession() {
sessionScore = 0
sessionLines = 0
sessionPieces = 0
sessionTime = 0
sessionLevel = 0
sessionSingles = 0
sessionDoubles = 0
sessionTriples = 0
sessionTetrises = 0
}
fun updateSessionStats(score: Int, lines: Int, pieces: Int, time: Long, level: Int) {
sessionScore = score
sessionLines = lines
sessionPieces = pieces
sessionTime = time
sessionLevel = level
}
fun recordLineClear(lineCount: Int) {
when (lineCount) {
1 -> {
sessionSingles++
totalSingles++
}
2 -> {
sessionDoubles++
totalDoubles++
}
3 -> {
sessionTriples++
totalTriples++
}
4 -> {
sessionTetrises++
totalTetrises++
}
}
}
fun endSession() {
totalGames++
totalScore += sessionScore
totalLines += sessionLines
totalPieces += sessionPieces
totalTime += sessionTime
if (sessionLevel > maxLevel) maxLevel = sessionLevel
if (sessionScore > maxScore) maxScore = sessionScore
if (sessionLines > maxLines) maxLines = sessionLines
saveStats()
}
// Getters for lifetime stats
fun getTotalGames(): Int = totalGames
fun getTotalScore(): Long = totalScore
fun getTotalLines(): Int = totalLines
fun getTotalPieces(): Int = totalPieces
fun getTotalTime(): Long = totalTime
fun getMaxLevel(): Int = maxLevel
fun getMaxScore(): Int = maxScore
fun getMaxLines(): Int = maxLines
// Getters for line clear stats (lifetime)
fun getTotalSingles(): Int = totalSingles
fun getTotalDoubles(): Int = totalDoubles
fun getTotalTriples(): Int = totalTriples
fun getTotalTetrises(): Int = totalTetrises
// Getters for session stats
fun getSessionScore(): Int = sessionScore
fun getSessionLines(): Int = sessionLines
fun getSessionPieces(): Int = sessionPieces
fun getSessionTime(): Long = sessionTime
fun getSessionLevel(): Int = sessionLevel
// Getters for line clear stats (session)
fun getSessionSingles(): Int = sessionSingles
fun getSessionDoubles(): Int = sessionDoubles
fun getSessionTriples(): Int = sessionTriples
fun getSessionTetrises(): Int = sessionTetrises
companion object {
private const val PREFS_NAME = "mintris_stats"
private const val KEY_TOTAL_GAMES = "total_games"
private const val KEY_TOTAL_SCORE = "total_score"
private const val KEY_TOTAL_LINES = "total_lines"
private const val KEY_TOTAL_PIECES = "total_pieces"
private const val KEY_TOTAL_TIME = "total_time"
private const val KEY_MAX_LEVEL = "max_level"
private const val KEY_MAX_SCORE = "max_score"
private const val KEY_MAX_LINES = "max_lines"
private const val KEY_TOTAL_SINGLES = "total_singles"
private const val KEY_TOTAL_DOUBLES = "total_doubles"
private const val KEY_TOTAL_TRIPLES = "total_triples"
private const val KEY_TOTAL_TETRISES = "total_tetrises"
}
}

View file

@ -135,10 +135,92 @@
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/finalScoreText"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:text="@string/session_stats"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginTop="24dp" />
<TextView
android:id="@+id/sessionScoreText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/sessionLinesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/sessionPiecesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/sessionTimeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/sessionLevelText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/line_clears"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginTop="16dp" />
<TextView
android:id="@+id/sessionSinglesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/sessionDoublesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/sessionTriplesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/sessionTetrisesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="18sp" /> android:textSize="18sp" />
@ -210,6 +292,16 @@
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="18sp" /> android:textSize="18sp" />
<Button
android:id="@+id/statsButton"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/transparent"
android:text="@string/stats"
android:textColor="@color/white"
android:textSize="18sp" />
<LinearLayout <LinearLayout
android:id="@+id/levelSelectorContainer" android:id="@+id/levelSelectorContainer"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lifetime_stats"
android:textColor="@color/white"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="24dp"/>
<TextView
android:id="@+id/totalGamesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/totalScoreText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/totalLinesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/totalPiecesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/totalTimeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="24dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/line_clears"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginBottom="16dp"/>
<TextView
android:id="@+id/totalSinglesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/totalDoublesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/totalTriplesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/totalTetrisesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="24dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/best_performance"
android:textColor="@color/white"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="24dp"/>
<TextView
android:id="@+id/maxLevelText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/maxScoreText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/maxLinesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="18sp"
android:layout_marginBottom="24dp"/>
<Button
android:id="@+id/backButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/back"
android:textColor="@color/white"
android:background="@color/transparent"
android:layout_marginTop="16dp"/>
</LinearLayout>
</ScrollView>

View file

@ -20,4 +20,28 @@
<string name="new_high_score">New High Score!</string> <string name="new_high_score">New High Score!</string>
<string name="save">Save</string> <string name="save">Save</string>
<string name="back">Back</string> <string name="back">Back</string>
<!-- Stats Screen -->
<string name="lifetime_stats">Lifetime Stats</string>
<string name="best_performance">Best Performance</string>
<string name="total_games">Total Games: %d</string>
<string name="total_score">Total Score: %d</string>
<string name="total_lines">Total Lines: %d</string>
<string name="total_pieces">Total Pieces: %d</string>
<string name="total_time">Total Time: %s</string>
<string name="max_level">Max Level: %d</string>
<string name="max_score">Max Score: %d</string>
<string name="max_lines">Max Lines: %d</string>
<string name="stats">Stats</string>
<string name="session_stats">Session Stats</string>
<string name="session_score">Score: %d</string>
<string name="session_lines">Lines: %d</string>
<string name="session_pieces">Pieces: %d</string>
<string name="session_time">Time: %s</string>
<string name="session_level">Level: %d</string>
<string name="line_clears">Line Clears</string>
<string name="singles">Singles: %d</string>
<string name="doubles">Doubles: %d</string>
<string name="triples">Triples: %d</string>
<string name="tetrises">Tetrises: %d</string>
</resources> </resources>