Skip to content

Commit

Permalink
add| new ui components and app structure
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriyPlatonov committed Jan 24, 2022
1 parent 90961fe commit c42b2eb
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 97 deletions.
5 changes: 3 additions & 2 deletions src/main/kotlin/MinesWeeperGame.kt
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class MinesWeeperGame(
private fun generatePoints(){
minerPoints.clear()
for (y in 1..gameType.h) {
for (x in 1..gameType.l){
for (x in 1..gameType.w){
val index = if(y > 9){
y * 100 + x
} else y * 100 + x
Expand Down Expand Up @@ -197,7 +197,7 @@ class MinesWeeperGame(
}
}

sealed class GameType(val h: Int, val l: Int) {
sealed class GameType(val h: Int, val w: Int) {
object Easy : GameType(8, 8)
object Medium : GameType(16, 16)
object Hard : GameType(16, 32)
Expand All @@ -209,6 +209,7 @@ class MinesWeeperGame(
Hard -> 99
}
}

fun getName(): String {
return when(this){
Easy -> "Новичек"
Expand Down
144 changes: 79 additions & 65 deletions src/main/kotlin/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,88 +7,96 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.FrameWindowScope
import androidx.compose.ui.window.MenuBar
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.singleWindowApplication
import androidx.compose.ui.unit.times
import androidx.compose.ui.window.*
import ui.GameGrid
import ui.MineSweeperStyles

@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
@Composable
@Preview
private fun App(globalWindowState: WindowState, windowScope: FrameWindowScope, minesWeeperGame: MinesWeeperGame) {
MaterialTheme {
private fun GameApp(
globalWindowState: WindowState,
windowScope: FrameWindowScope,
minesWeeperGame: MinesWeeperGame,
onCloseRequest: () -> Unit
) = MaterialTheme {

val gameState: MinesWeeperGame.GameState? by minesWeeperGame.gameState.collectAsState(null)
val gameState: MinesWeeperGame.GameState? by minesWeeperGame.gameState.collectAsState(null)

if(gameState == null) return@MaterialTheme
if(gameState == null) return@MaterialTheme

println("trigger game state is $gameState")
val gameTimer: Int by gameState!!.gameTimer.timerStateFlow.collectAsState(0)
val gameNumber = gameState!!.gameNumber
val gameType = gameState!!.gameType
val gameStatus = gameState!!.gameStatus

val gameNumber = gameState!!.gameNumber
val gameType = gameState!!.gameType
val gameStatus = gameState!!.gameStatus
val gameTimer = remember { mutableStateOf(0) }
val topRowColor = animateColorAsState(
when(gameStatus){
MinesWeeperGame.GameStatus.Win -> MineSweeperStyles.winGameBackground
MinesWeeperGame.GameStatus.Losing -> MineSweeperStyles.loseGameBackground
else -> MineSweeperStyles.inGameBackground
}
)

val topRowColor = animateColorAsState(
when(gameStatus){
MinesWeeperGame.GameStatus.Win -> Color.Green
MinesWeeperGame.GameStatus.Losing -> Color.Red
else -> Color.Transparent
}
Column(
modifier = Modifier.background(topRowColor.value).padding(MineSweeperStyles.windowPaddingSize),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top
) {
TopMenu(
minesCount = "${gameState?.minePoints ?: gameType.getMineCount()}",
statusName = gameStatus.getStatusName(),
timerValue = gameTimer.toString()
)

Column(
modifier = Modifier.background(topRowColor.value).padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top
) {
TopMenu(
minesCount = "${gameState?.minePoints ?: gameType.getMineCount()}",
statusName = gameStatus.getStatusName(),
timerValue = gameTimer.value.toString()
)

GameGrid(gameNumber, gameType, gameState!!){ onClickSellEvent ->
when(onClickSellEvent){
is OnCellClickEvent.OnSingleClick -> minesWeeperGame.openPoint(onClickSellEvent.index)
is OnCellClickEvent.OnLongClick -> minesWeeperGame.markPoint(onClickSellEvent.index)
is OnCellClickEvent.OnDoubleClick -> minesWeeperGame.openRadianPoints(onClickSellEvent.index)
}
GameGrid(gameNumber, gameType, gameState!!){ onClickSellEvent ->
when(onClickSellEvent){
is OnCellClickEvent.OnSingleClick -> minesWeeperGame.openPoint(onClickSellEvent.index)
is OnCellClickEvent.OnLongClick -> minesWeeperGame.markPoint(onClickSellEvent.index)
is OnCellClickEvent.OnDoubleClick -> minesWeeperGame.openRadianPoints(onClickSellEvent.index)
}
}
}

LaunchedEffect(gameType.h, gameType.l){
globalWindowState.size = DpSize.Unspecified
}
LaunchedEffect(gameType.h, gameType.w){
val width = (gameType.w * MineSweeperStyles.cellSize) + MineSweeperStyles.windowPaddingSize * 2
val height = (gameType.h * MineSweeperStyles.cellSize) +
MineSweeperStyles.windowPaddingSize * 4 + MineSweeperStyles.topMenuHeightSize

windowScope.MenuBar {
Menu("Игра") {
Item("Новая игра", onClick = {
minesWeeperGame.resetGame()
globalWindowState.size = globalWindowState.size.copy(width = width, height = height)
}

windowScope.MenuBar {
Menu("Игра") {
Item("Новая игра", onClick = {
minesWeeperGame.resetGame()
})
Menu(
"Сложность"
){
Item(MinesWeeperGame.GameType.Easy.getName(), onClick = {
minesWeeperGame.changeGameType(MinesWeeperGame.GameType.Easy)
})
Item(MinesWeeperGame.GameType.Medium.getName(), onClick = {
minesWeeperGame.changeGameType(MinesWeeperGame.GameType.Medium)
})
Item(MinesWeeperGame.GameType.Hard.getName(), onClick = {
minesWeeperGame.changeGameType(MinesWeeperGame.GameType.Hard)
})
Menu(
"Сложность"
){
Item(MinesWeeperGame.GameType.Easy.getName(), onClick = {
minesWeeperGame.changeGameType(MinesWeeperGame.GameType.Easy)
})
Item(MinesWeeperGame.GameType.Medium.getName(), onClick = {
minesWeeperGame.changeGameType(MinesWeeperGame.GameType.Medium)
})
Item(MinesWeeperGame.GameType.Hard.getName(), onClick = {
minesWeeperGame.changeGameType(MinesWeeperGame.GameType.Hard)
})
}
Item("Выход", onClick = {})
}
Item("Выход", onClick = {
onCloseRequest()
})
}
}
}
Expand All @@ -98,10 +106,16 @@ fun main() {
val globalWindowState = WindowState(size = DpSize.Unspecified)
val minesWeeperGame = MinesWeeperGame()

singleWindowApplication(
title = "MineSweeper",
state = globalWindowState
) {
App(globalWindowState, this, minesWeeperGame)
application {

Window(
icon = painterResource(MineSweeperStyles.cellIsMarkIconSrc),
title = "MineSweeper",
onCloseRequest = ::exitApplication,
resizable = false,
state = globalWindowState,
){
GameApp(globalWindowState, this, minesWeeperGame, ::exitApplication)
}
}
}
65 changes: 39 additions & 26 deletions src/main/kotlin/ui/GameGrid.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
package ui

import MinesWeeperGame
import OnCellClickEvent
import model.MinerPoint
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.isSecondaryPressed
import androidx.compose.ui.input.pointer.onPointerEvent
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import model.MinerPoint

@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
@Composable
Expand All @@ -31,7 +29,7 @@ internal fun GameGrid(
){
for (y in 1..gameType.h) {
Row {
for (x in 1..gameType.l) {
for (x in 1..gameType.w) {
val index = remember(x, y) {
if (y > 9) {
y * 100 + x
Expand All @@ -56,13 +54,13 @@ internal fun GameSell(
point: MinerPoint,
onClickEventListener: (OnCellClickEvent) -> Unit
) {
val background = animateColorAsState(if (point.isOpen) Color.LightGray else Color.Gray)
val background = animateColorAsState(if (point.isOpen) MineSweeperStyles.cellOpenColor else MineSweeperStyles.cellCloseColor)

Box(
modifier = Modifier
.background(background.value)
.border(BorderStroke(1.dp, Color.DarkGray))
.size(25.dp, 25.dp)
.border(BorderStroke(MineSweeperStyles.cellBorderSize, MineSweeperStyles.cellBorderColor))
.size(MineSweeperStyles.cellSize, MineSweeperStyles.cellSize)
.onPointerEvent(PointerEventType.Press) {
if (it.buttons.isSecondaryPressed) {
onClickEventListener(OnCellClickEvent.OnLongClick(index))
Expand All @@ -81,29 +79,44 @@ internal fun GameSell(
),
contentAlignment = Alignment.Center
) {
println("test for create item $index")
val minesCount = remember(gameNumber, index) {
if (point.radianMineCount > 0) "${point.radianMineCount}"
else ""
}
if (point.isOpen && point.isMine) {
Text(
text = "*",
color = Color.Red,
fontWeight = FontWeight.ExtraBold
)
Mine()
} else if (point.isOpen) {
Text(
modifier = Modifier.padding(0.dp),
text = minesCount,
color = Color.Blue,
fontWeight = FontWeight.ExtraBold
)
Open(minesCount)
} else if (point.isMark) {
Text(
modifier = Modifier.padding(0.dp),
text = "M",
color = Color.Yellow
)
Flag()
}
}
}

@Composable
internal fun Open(minesCount: String){
Text(
modifier = Modifier.padding(0.dp),
text = minesCount,
color = MineSweeperStyles.cellFontColor,
fontWeight = FontWeight.ExtraBold
)
}

@Composable
internal fun Mine(){
Image(
painter = painterResource(MineSweeperStyles.cellIsBombIconSrc),
contentDescription = "",
modifier = Modifier.fillMaxSize()
)
}
@Composable
internal fun Flag(){
Image(
painter = painterResource(MineSweeperStyles.cellIsMarkIconSrc),
contentDescription = "",
modifier = Modifier.fillMaxSize()
)
}
8 changes: 4 additions & 4 deletions src/main/kotlin/ui/TopMenu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import ui.MineSweeperStyles

@Composable
internal fun TopMenu(
Expand All @@ -16,9 +16,9 @@ internal fun TopMenu(
){
Row(
modifier = Modifier
.padding(bottom = 8.dp)
.width(200.dp)
.padding(start = 8.dp, end = 8.dp),
.padding(bottom = MineSweeperStyles.windowPaddingSize)
.width(MineSweeperStyles.topMenuWidthSize)
.padding(start = MineSweeperStyles.windowPaddingSize, end = MineSweeperStyles.windowPaddingSize),
horizontalArrangement = Arrangement.Center
) {
Text(
Expand Down

0 comments on commit c42b2eb

Please sign in to comment.