Merge branch 'add-support-screen' of github.com:lucasnlm/antimine-android into add-support-screen
|
@ -10,7 +10,7 @@ android {
|
|||
// versionCode and versionName must be hardcoded to support F-droid
|
||||
versionCode 800051
|
||||
versionName '8.0.5'
|
||||
minSdkVersion 16
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
multiDexEnabled true
|
||||
vectorDrawables.useSupportLibrary true
|
||||
|
|
|
@ -106,7 +106,6 @@ class GameFlowTests {
|
|||
.perform(NavigationViewActions.navigateTo(R.id.control))
|
||||
|
||||
onView(withText(R.string.standard)).perform(click())
|
||||
onView(withText(R.string.flag_first)).perform(click())
|
||||
|
||||
onView(withText(R.string.ok)).perform(click())
|
||||
}
|
||||
|
|
|
@ -45,10 +45,11 @@ class AboutViewModel(
|
|||
|
||||
private fun getLicensesList() = mapOf(
|
||||
"Android SDK License" to R.raw.android_sdk,
|
||||
"Material Design Icons" to R.raw.apache2,
|
||||
"Material Design" to R.raw.apache2,
|
||||
"Dagger Hilt" to R.raw.apache2,
|
||||
"Moshi" to R.raw.apache2,
|
||||
"Mockito" to R.raw.mockito,
|
||||
"Noto Emoji" to R.raw.apache2,
|
||||
"Sounds" to R.raw.sounds
|
||||
).map {
|
||||
License(it.key, it.value)
|
||||
|
|
|
@ -29,7 +29,7 @@ class HistoryViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun mapEventToState(event: HistoryEvent) = flow<HistoryState> {
|
||||
override suspend fun mapEventToState(event: HistoryEvent) = flow {
|
||||
when (event) {
|
||||
is HistoryEvent.LoadAllSaves -> {
|
||||
val newSaveList = savesRepository.getAllSaves().sortedByDescending { it.uid }
|
||||
|
|
|
@ -66,13 +66,6 @@ open class LevelFragment : CommonLevelFragment(R.layout.fragment_level) {
|
|||
}
|
||||
)
|
||||
|
||||
fieldRefresh.observe(
|
||||
viewLifecycleOwner,
|
||||
Observer {
|
||||
areaAdapter.notifyItemChanged(it)
|
||||
}
|
||||
)
|
||||
|
||||
eventObserver.observe(
|
||||
viewLifecycleOwner,
|
||||
Observer {
|
||||
|
|
|
@ -73,7 +73,7 @@ class EndGameDialogViewModel(
|
|||
false
|
||||
)
|
||||
|
||||
override suspend fun mapEventToState(event: EndGameDialogEvent) = flow<EndGameDialogState> {
|
||||
override suspend fun mapEventToState(event: EndGameDialogEvent) = flow {
|
||||
if (event is EndGameDialogEvent.BuildCustomEndGame) {
|
||||
val state = when (event.isVictory) {
|
||||
true -> {
|
||||
|
|
|
@ -39,8 +39,6 @@ class ThemeActivity : ThematicActivity(R.layout.activity_theme) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
showUnlockDialog()
|
||||
}
|
||||
|
||||
private fun showUnlockDialog() {
|
||||
|
|
|
@ -58,14 +58,27 @@ class ThemeAdapter(
|
|||
val theme = themes[position]
|
||||
val paintSettings = createAreaPaintSettings(holder.itemView.context, areaSize)
|
||||
holder.itemView.run {
|
||||
val selected = (theme.id == themeViewModel.singleState().current.id)
|
||||
val areas = listOf(area0, area1, area2, area3, area4, area5, area6, area7, area8)
|
||||
|
||||
if (selected) {
|
||||
areas.forEach { it.alpha = 0.25f }
|
||||
} else {
|
||||
areas.forEach { it.alpha = 1.0f }
|
||||
}
|
||||
|
||||
areas.forEachIndexed { index, areaView -> areaView.bindTheme(minefield[index], theme, paintSettings) }
|
||||
|
||||
if (position == 0) {
|
||||
if (position < 2 && !selected) {
|
||||
areas.forEach { it.alpha = 0.35f }
|
||||
|
||||
label.apply {
|
||||
text = if (position == 0) {
|
||||
label.context.getString(R.string.system)
|
||||
} else {
|
||||
label.context.getString(R.string.amoled)
|
||||
}
|
||||
|
||||
setTextColor(
|
||||
with(theme.palette.background) {
|
||||
Color.rgb(255 - Color.red(this), 255 - Color.green(this), 255 - Color.blue(this))
|
||||
|
|
|
@ -12,7 +12,7 @@ class ThemeViewModel(
|
|||
themeRepository.setTheme(theme)
|
||||
}
|
||||
|
||||
override suspend fun mapEventToState(event: ThemeEvent) = flow<ThemeState> {
|
||||
override suspend fun mapEventToState(event: ThemeEvent) = flow {
|
||||
if (event is ThemeEvent.ChangeTheme) {
|
||||
setTheme(event.newTheme)
|
||||
emit(state.copy(current = event.newTheme))
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:includeFontPadding="false"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
@ -10,7 +11,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:elevation="0dp"
|
||||
android:minHeight="30dp"
|
||||
android:theme="@style/AppTheme.AppBarOverlay"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:targetApi="lollipop" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -29,9 +30,6 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:drawableStart="@drawable/timer"
|
||||
android:drawableLeft="@drawable/timer"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:includeFontPadding="false"
|
||||
|
@ -41,6 +39,8 @@
|
|||
android:textSize="@dimen/text_size"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
app:drawableLeftCompat="@drawable/timer"
|
||||
app:drawableStartCompat="@drawable/timer"
|
||||
tools:text="10:00"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
@ -49,8 +49,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:drawableStart="@drawable/mine"
|
||||
android:drawableLeft="@drawable/mine"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:includeFontPadding="false"
|
||||
|
@ -59,6 +57,7 @@
|
|||
android:textSize="@dimen/text_size"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/mine"
|
||||
tools:text="99"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
|
|
@ -13,13 +13,14 @@
|
|||
android:layout_height="64dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:focusable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/emoji_smiling_face_with_sunglasses" />
|
||||
tools:src="@drawable/emoji_smiling_face_with_sunglasses"
|
||||
tools:ignore="KeyboardInaccessibleWidget" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingLeft="32dp"
|
||||
android:paddingRight="48dp"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="48dp"
|
||||
android:paddingVertical="12dp">
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintStart_toEndOf="@id/badge"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
@ -35,7 +34,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintStart_toEndOf="@id/badge"
|
||||
app:layout_constraintTop_toBottomOf="@id/difficulty"
|
||||
|
@ -46,7 +44,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="-"
|
||||
app:layout_constraintStart_toEndOf="@id/minefieldSize"
|
||||
|
@ -58,7 +55,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layout_constraintStart_toEndOf="@id/dash"
|
||||
app:layout_constraintTop_toBottomOf="@id/difficulty"
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
android:layout_weight="1"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
tools:text="Text" />
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:columnCount="3"
|
||||
android:background="#FFFF0000"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
|
|
|
@ -10,7 +10,7 @@ android {
|
|||
// versionCode and versionName must be hardcoded to support F-droid
|
||||
versionCode 800051
|
||||
versionName '8.0.5'
|
||||
minSdkVersion 16
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 664 B After Width: | Height: | Size: 695 B |
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 807 B |
Before Width: | Height: | Size: 864 B After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 969 B After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 647 B After Width: | Height: | Size: 689 B |
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 807 B |
Before Width: | Height: | Size: 664 B After Width: | Height: | Size: 695 B |
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 807 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 865 B After Width: | Height: | Size: 936 B |
Before Width: | Height: | Size: 1,001 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 743 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 654 B |
Before Width: | Height: | Size: 726 B After Width: | Height: | Size: 743 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -10,13 +10,11 @@ import dev.lucasnlm.antimine.common.level.logic.MinefieldHandler
|
|||
import dev.lucasnlm.antimine.common.level.logic.filterNeighborsOf
|
||||
import dev.lucasnlm.antimine.common.level.models.Area
|
||||
import dev.lucasnlm.antimine.common.level.models.Difficulty
|
||||
import dev.lucasnlm.antimine.common.level.models.Mark
|
||||
import dev.lucasnlm.antimine.common.level.models.Minefield
|
||||
import dev.lucasnlm.antimine.common.level.models.Score
|
||||
import dev.lucasnlm.antimine.common.level.solver.LimitedBruteForceSolver
|
||||
import dev.lucasnlm.antimine.core.control.ActionResponse
|
||||
import dev.lucasnlm.antimine.core.control.GameControl
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlin.random.Random
|
||||
|
||||
|
@ -53,6 +51,8 @@ class GameController {
|
|||
|
||||
fun field() = field
|
||||
|
||||
fun field(predicate: (Area) -> Boolean) = field.filter(predicate)
|
||||
|
||||
fun mines() = field.filter { it.hasMine }
|
||||
|
||||
fun hasMines() = field.firstOrNull { it.hasMine } != null
|
||||
|
@ -167,7 +167,7 @@ class GameController {
|
|||
}
|
||||
}
|
||||
|
||||
fun findExplodedMine() = mines().filter { it.mistake }.firstOrNull()
|
||||
fun findExplodedMine() = mines().firstOrNull { it.mistake }
|
||||
|
||||
fun takeExplosionRadius(target: Area): List<Area> =
|
||||
mines().filter { it.isCovered && it.mark.isNone() }.sortedBy {
|
||||
|
@ -192,7 +192,7 @@ class GameController {
|
|||
|
||||
fun showWrongFlags() {
|
||||
field = field.map {
|
||||
if (it.mark.isNotNone() && !it.hasMine) {
|
||||
if (!it.hasMine && it.mark.isFlag()) {
|
||||
it.copy(mistake = true)
|
||||
} else {
|
||||
it
|
||||
|
|
|
@ -8,14 +8,13 @@ class MinefieldHandler(
|
|||
private val useQuestionMark: Boolean
|
||||
) {
|
||||
fun showAllMines() {
|
||||
field.filter { it.hasMine && it.mark != Mark.Flag}
|
||||
field.filter { it.hasMine && it.mark != Mark.Flag }
|
||||
.forEach { field[it.id] = it.copy(isCovered = false) }
|
||||
}
|
||||
|
||||
fun flagAllMines() {
|
||||
field.filter { it.hasMine }
|
||||
.forEach { field[it.id] = it.copy(mark = Mark.Flag) }
|
||||
|
||||
}
|
||||
|
||||
fun revealAllEmptyAreas() {
|
||||
|
@ -86,16 +85,15 @@ class MinefieldHandler(
|
|||
if (flaggedCount >= minesAround) {
|
||||
neighbors
|
||||
.filter { it.isCovered && it.mark.isNone() }
|
||||
.onEach { openAt(it.id, passive = false, openNeighbors = true) }
|
||||
.count()
|
||||
.forEach { openAt(it.id, passive = false, openNeighbors = true) }
|
||||
} else {
|
||||
val coveredNeighbors = neighbors.filter { it.isCovered }
|
||||
if (coveredNeighbors.count() == minesAround) {
|
||||
coveredNeighbors.filter {
|
||||
it.mark.isNone()
|
||||
}.onEach {
|
||||
}.forEach {
|
||||
switchMarkAt(it.id)
|
||||
}.count()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@ class DimensionRepository(
|
|||
}
|
||||
|
||||
override fun navigationBarHeight(): Int {
|
||||
// TODO use official mode if available
|
||||
val resources = context.resources
|
||||
val resourceId: Int = resources.getIdentifier(NAVIGATION_BAR_HEIGHT, DEF_TYPE_DIMEN, DEF_PACKAGE)
|
||||
return if (resourceId > 0) { resources.getDimensionPixelSize(resourceId) } else 0
|
||||
|
|
|
@ -9,9 +9,7 @@ open class BruteForceSolver : GameSolver() {
|
|||
|
||||
do {
|
||||
val initialMap = minefield.filter { !it.isCovered && it.minesAround != 0 }
|
||||
initialMap.forEach {
|
||||
minefieldHandler.openOrFlagNeighborsOf(it.id)
|
||||
}
|
||||
initialMap.forEach { minefieldHandler.openOrFlagNeighborsOf(it.id) }
|
||||
} while (initialMap != minefield.filter { !it.isCovered && it.minesAround != 0 })
|
||||
|
||||
return minefield.count { it.hasMine && !it.mark.isFlag() } == 0
|
||||
|
|
|
@ -57,17 +57,19 @@ class AreaAdapter(
|
|||
override fun getItemCount(): Int = field.size
|
||||
|
||||
private fun AreaView.onClickablePosition(position: Int, action: suspend (Int) -> Unit): Boolean {
|
||||
return if (position == RecyclerView.NO_POSITION) {
|
||||
Log.d(TAG, "Item no longer exists.")
|
||||
false
|
||||
} else if (clickEnabled) {
|
||||
requestFocus()
|
||||
GlobalScope.launch {
|
||||
action(position)
|
||||
return when {
|
||||
position == RecyclerView.NO_POSITION -> {
|
||||
Log.d(TAG, "Item no longer exists.")
|
||||
false
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
clickEnabled -> {
|
||||
requestFocus()
|
||||
GlobalScope.launch {
|
||||
action(position)
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,12 +106,7 @@ class AreaView : View {
|
|||
area.hasMine -> IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||
area.mistake -> IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||
area.mark.isNotNone() -> IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||
!area.isCovered ->
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
||||
} else {
|
||||
IMPORTANT_FOR_ACCESSIBILITY_NO
|
||||
}
|
||||
!area.isCovered -> IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
||||
else -> IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||
}
|
||||
)
|
||||
|
|
|
@ -53,7 +53,6 @@ class GameViewModel(
|
|||
private var currentDifficulty: Difficulty = Difficulty.Standard
|
||||
|
||||
val field = MutableLiveData<List<Area>>()
|
||||
val fieldRefresh = MutableLiveData<Int>()
|
||||
val elapsedTimeSeconds = MutableLiveData<Long>()
|
||||
val mineCount = MutableLiveData<Int>()
|
||||
val difficulty = MutableLiveData<Difficulty>()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package dev.lucasnlm.antimine.core.di
|
||||
|
||||
import android.view.ViewConfiguration
|
||||
import dev.lucasnlm.antimine.common.level.repository.DimensionRepository
|
||||
import dev.lucasnlm.antimine.common.level.repository.IDimensionRepository
|
||||
import dev.lucasnlm.antimine.core.preferences.IPreferencesManager
|
||||
|
@ -18,7 +19,7 @@ val CommonModule = module {
|
|||
|
||||
single { DimensionRepository(get(), get()) } bind IDimensionRepository::class
|
||||
|
||||
single { PreferencesRepository(get()) } bind IPreferencesRepository::class
|
||||
single { PreferencesRepository(get(), ViewConfiguration.getLongPressTimeout()) } bind IPreferencesRepository::class
|
||||
|
||||
single { SoundManager(get()) } bind ISoundManager::class
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ interface IPreferencesRepository {
|
|||
}
|
||||
|
||||
class PreferencesRepository(
|
||||
private val preferencesManager: IPreferencesManager
|
||||
private val preferencesManager: IPreferencesManager,
|
||||
private val defaultLongPressTimeout: Int
|
||||
) : IPreferencesRepository {
|
||||
init {
|
||||
migrateOldPreferences()
|
||||
|
@ -151,7 +152,7 @@ class PreferencesRepository(
|
|||
}
|
||||
|
||||
if (!preferencesManager.contains(PREFERENCE_LONG_PRESS_TIMEOUT)) {
|
||||
preferencesManager.putInt(PREFERENCE_LONG_PRESS_TIMEOUT, ViewConfiguration.getLongPressTimeout())
|
||||
preferencesManager.putInt(PREFERENCE_LONG_PRESS_TIMEOUT, defaultLongPressTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,17 @@ import dev.lucasnlm.antimine.core.themes.model.AreaPalette
|
|||
import dev.lucasnlm.antimine.core.preferences.IPreferencesRepository
|
||||
import dev.lucasnlm.antimine.core.themes.model.AppTheme
|
||||
import dev.lucasnlm.antimine.core.themes.model.Assets
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.AmoledTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.BlueGreyTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.BrownTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.ChessTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.DarkTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.GardenTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.LightTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.MarineTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.OrangeTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.PinkTheme
|
||||
import dev.lucasnlm.antimine.core.themes.repository.Themes.PurpleTheme
|
||||
|
||||
interface IThemeRepository {
|
||||
fun getCustomTheme(): AppTheme?
|
||||
|
@ -33,7 +39,10 @@ class ThemeRepository(
|
|||
}
|
||||
|
||||
override fun getAllThemes(): List<AppTheme> = listOf(
|
||||
buildSystemTheme(), LightTheme, DarkTheme, GardenTheme, MarineTheme, ChessTheme
|
||||
buildSystemTheme(), AmoledTheme, LightTheme,
|
||||
DarkTheme, GardenTheme, MarineTheme,
|
||||
ChessTheme, BlueGreyTheme, OrangeTheme,
|
||||
PinkTheme, PurpleTheme, BrownTheme
|
||||
)
|
||||
|
||||
override fun setTheme(theme: AppTheme) {
|
||||
|
|
|
@ -39,8 +39,41 @@ object Themes {
|
|||
)
|
||||
)
|
||||
|
||||
val DarkTheme = AppTheme(
|
||||
val AmoledTheme = AppTheme(
|
||||
id = 2L,
|
||||
theme = R.style.CustomAmoledTheme,
|
||||
themeNoActionBar = R.style.CustomAmoledTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
border = 0xFFFFFF,
|
||||
background = 0x000000,
|
||||
covered = 0x212121,
|
||||
coveredOdd = 0x212121,
|
||||
uncovered = 0x000000,
|
||||
uncoveredOdd = 0x050505,
|
||||
minesAround1 = 0xCCCCCC,
|
||||
minesAround2 = 0xFFFFFF,
|
||||
minesAround3 = 0xDDDDDD,
|
||||
minesAround4 = 0xCCCCCC,
|
||||
minesAround5 = 0xDDDDDD,
|
||||
minesAround6 = 0xFFFFFF,
|
||||
minesAround7 = 0xCCCCCC,
|
||||
minesAround8 = 0xCCCCCC,
|
||||
highlight = 0x212121,
|
||||
focus = 0xD32F2F
|
||||
),
|
||||
assets = Assets(
|
||||
wrongFlag = R.drawable.flag,
|
||||
flag = R.drawable.flag,
|
||||
questionMark = R.drawable.question,
|
||||
toolbarMine = R.drawable.mine_low,
|
||||
mine = R.drawable.mine_low,
|
||||
mineExploded = R.drawable.mine_low,
|
||||
mineLow = R.drawable.mine_low
|
||||
)
|
||||
)
|
||||
|
||||
val DarkTheme = AppTheme(
|
||||
id = 3L,
|
||||
theme = R.style.CustomDarkTheme,
|
||||
themeNoActionBar = R.style.CustomDarkTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
|
@ -73,7 +106,7 @@ object Themes {
|
|||
)
|
||||
|
||||
val GardenTheme = AppTheme(
|
||||
id = 3L,
|
||||
id = 4L,
|
||||
theme = R.style.CustomGardenTheme,
|
||||
themeNoActionBar = R.style.CustomGardenTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
|
@ -106,7 +139,7 @@ object Themes {
|
|||
)
|
||||
|
||||
val ChessTheme = AppTheme(
|
||||
id = 4L,
|
||||
id = 5L,
|
||||
theme = R.style.CustomLightTheme,
|
||||
themeNoActionBar = R.style.CustomLightTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
|
@ -139,7 +172,7 @@ object Themes {
|
|||
)
|
||||
|
||||
val MarineTheme = AppTheme(
|
||||
id = 5L,
|
||||
id = 6L,
|
||||
theme = R.style.CustomMarineTheme,
|
||||
themeNoActionBar = R.style.CustomMarineTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
|
@ -170,4 +203,169 @@ object Themes {
|
|||
mineLow = R.drawable.mine_low
|
||||
)
|
||||
)
|
||||
|
||||
val BlueGreyTheme = AppTheme(
|
||||
id = 7L,
|
||||
theme = R.style.CustomBlueGreyTheme,
|
||||
themeNoActionBar = R.style.CustomBlueGreyTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
border = 0x424242,
|
||||
background = 0xFFFFFF,
|
||||
covered = 0x37474f,
|
||||
coveredOdd = 0x37474f,
|
||||
uncovered = 0xcfd8dc,
|
||||
uncoveredOdd = 0xcfd8dc,
|
||||
minesAround1 = 0x527F8D,
|
||||
minesAround2 = 0x2B8D43,
|
||||
minesAround3 = 0x546e7a,
|
||||
minesAround4 = 0x20A5f7,
|
||||
minesAround5 = 0xED1C24,
|
||||
minesAround6 = 0xFFC107,
|
||||
minesAround7 = 0x66126B,
|
||||
minesAround8 = 0x000000,
|
||||
highlight = 0x212121,
|
||||
focus = 0xD32F2F
|
||||
),
|
||||
assets = Assets(
|
||||
wrongFlag = R.drawable.red_flag,
|
||||
flag = R.drawable.flag,
|
||||
questionMark = R.drawable.question,
|
||||
toolbarMine = R.drawable.mine,
|
||||
mine = R.drawable.mine,
|
||||
mineExploded = R.drawable.mine_exploded_red,
|
||||
mineLow = R.drawable.mine_low
|
||||
)
|
||||
)
|
||||
|
||||
val OrangeTheme = AppTheme(
|
||||
id = 8L,
|
||||
theme = R.style.CustomOrangeTheme,
|
||||
themeNoActionBar = R.style.CustomOrangeTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
border = 0x000000,
|
||||
background = 0x212121,
|
||||
covered = 0xfb8c00,
|
||||
coveredOdd = 0xfb8c00,
|
||||
uncovered = 0x303030,
|
||||
uncoveredOdd = 0x252525,
|
||||
minesAround1 = 0xDDDDDD,
|
||||
minesAround2 = 0xEEEEEE,
|
||||
minesAround3 = 0xCCCCCC,
|
||||
minesAround4 = 0xBBBBBB,
|
||||
minesAround5 = 0xAAAAAA,
|
||||
minesAround6 = 0xFFFFFF,
|
||||
minesAround7 = 0xBBBBBB,
|
||||
minesAround8 = 0xEEEEEE,
|
||||
highlight = 0x212121,
|
||||
focus = 0xD32F2F
|
||||
),
|
||||
assets = Assets(
|
||||
wrongFlag = R.drawable.flag_black,
|
||||
flag = R.drawable.flag_black,
|
||||
questionMark = R.drawable.question_black,
|
||||
toolbarMine = R.drawable.mine_low,
|
||||
mine = R.drawable.mine_white,
|
||||
mineExploded = R.drawable.mine_white,
|
||||
mineLow = R.drawable.mine_low
|
||||
)
|
||||
)
|
||||
|
||||
val PinkTheme = AppTheme(
|
||||
id = 9L,
|
||||
theme = R.style.CustomPinkTheme,
|
||||
themeNoActionBar = R.style.CustomPinkTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
border = 0x000000,
|
||||
background = 0xFFFFFF,
|
||||
covered = 0xf48fb1,
|
||||
coveredOdd = 0xf48fb1,
|
||||
uncovered = 0xfce4ec,
|
||||
uncoveredOdd = 0xfce4ec,
|
||||
minesAround1 = 0x616161,
|
||||
minesAround2 = 0xe64a19,
|
||||
minesAround3 = 0x8e24aa,
|
||||
minesAround4 = 0x000000,
|
||||
minesAround5 = 0x1e88e5,
|
||||
minesAround6 = 0x424242,
|
||||
minesAround7 = 0x616161,
|
||||
minesAround8 = 0x000000,
|
||||
highlight = 0x212121,
|
||||
focus = 0xD32F2F
|
||||
),
|
||||
assets = Assets(
|
||||
wrongFlag = R.drawable.flag,
|
||||
flag = R.drawable.flag,
|
||||
questionMark = R.drawable.question,
|
||||
toolbarMine = R.drawable.mine_low,
|
||||
mine = R.drawable.mine_pink,
|
||||
mineExploded = R.drawable.mine_pink_exploded,
|
||||
mineLow = R.drawable.mine_low
|
||||
)
|
||||
)
|
||||
|
||||
val PurpleTheme = AppTheme(
|
||||
id = 10L,
|
||||
theme = R.style.CustomPurpleTheme,
|
||||
themeNoActionBar = R.style.CustomPurpleTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
border = 0x000000,
|
||||
background = 0xFFFFFF,
|
||||
covered = 0x6a1b9a,
|
||||
coveredOdd = 0x6a1b9a,
|
||||
uncovered = 0xd1c4e9,
|
||||
uncoveredOdd = 0xd1c4e9,
|
||||
minesAround1 = 0x616161,
|
||||
minesAround2 = 0xe64a19,
|
||||
minesAround3 = 0x8e24aa,
|
||||
minesAround4 = 0x000000,
|
||||
minesAround5 = 0x1e88e5,
|
||||
minesAround6 = 0x424242,
|
||||
minesAround7 = 0x616161,
|
||||
minesAround8 = 0x000000,
|
||||
highlight = 0xd1c4e9,
|
||||
focus = 0xD32F2F
|
||||
),
|
||||
assets = Assets(
|
||||
wrongFlag = R.drawable.flag,
|
||||
flag = R.drawable.flag,
|
||||
questionMark = R.drawable.question,
|
||||
toolbarMine = R.drawable.mine_low,
|
||||
mine = R.drawable.mine_pink,
|
||||
mineExploded = R.drawable.mine_pink_exploded,
|
||||
mineLow = R.drawable.mine_low
|
||||
)
|
||||
)
|
||||
|
||||
val BrownTheme = AppTheme(
|
||||
id = 11L,
|
||||
theme = R.style.CustomLightTheme,
|
||||
themeNoActionBar = R.style.CustomLightTheme_NoActionBar,
|
||||
palette = AreaPalette(
|
||||
border = 0x000000,
|
||||
background = 0xFFFFFF,
|
||||
covered = 0x3e2723,
|
||||
coveredOdd = 0x4e342e,
|
||||
uncovered = 0xd7ccc8,
|
||||
uncoveredOdd = 0xefebe9,
|
||||
minesAround1 = 0x616161,
|
||||
minesAround2 = 0xe64a19,
|
||||
minesAround3 = 0x8e24aa,
|
||||
minesAround4 = 0x000000,
|
||||
minesAround5 = 0x1e88e5,
|
||||
minesAround6 = 0x424242,
|
||||
minesAround7 = 0x616161,
|
||||
minesAround8 = 0x000000,
|
||||
highlight = 0xd1c4e9,
|
||||
focus = 0xD32F2F
|
||||
),
|
||||
assets = Assets(
|
||||
wrongFlag = R.drawable.flag,
|
||||
flag = R.drawable.flag,
|
||||
questionMark = R.drawable.question,
|
||||
toolbarMine = R.drawable.mine_low,
|
||||
mine = R.drawable.mine,
|
||||
mineExploded = R.drawable.mine_pink_exploded,
|
||||
mineLow = R.drawable.mine_low
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
9
common/src/main/res/drawable/flag_black.xml
Executable file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF212121"
|
||||
android:pathData="M14.4,6L14,4H5v17h2v-7h5.6l0.4,2h7V6z" />
|
||||
</vector>
|
14
common/src/main/res/drawable/mine_pink.xml
Executable file
|
@ -0,0 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#450220"
|
||||
android:pathData="M331.722,124.091l-33.743,-67.204l-83.901,0l-33.84,65.28l-80.22,0l-37.443,65.714l37.443,67.649l-37.443,66.12l37.42,67.746l80.243,0l39.239,65.717l75.084,0l37.161,-66.643l79.759,-0.019l37.942,-66.801l-40.501,-65.64l40.501,-68.129l-38.02,-63.79z"
|
||||
android:strokeWidth="0.02435089" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#450220"
|
||||
android:pathData="M360.853,255.692l-52.193,91.05l-104.8,0.177l-52.713,-90.616l52.081,-90.835l104.896,-0.386z" />
|
||||
</vector>
|
14
common/src/main/res/drawable/mine_pink_exploded.xml
Executable file
|
@ -0,0 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#450220"
|
||||
android:pathData="M331.722,124.091l-33.743,-67.204l-83.901,0l-33.84,65.28l-80.22,0l-37.443,65.714l37.443,67.649l-37.443,66.12l37.42,67.746l80.243,0l39.239,65.717l75.084,0l37.161,-66.643l79.759,-0.019l37.942,-66.801l-40.501,-65.64l40.501,-68.129l-38.02,-63.79z"
|
||||
android:strokeWidth="0.02435089" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#d81b60"
|
||||
android:pathData="M360.853,255.692l-52.193,91.05l-104.8,0.177l-52.713,-90.616l52.081,-90.835l104.896,-0.386z" />
|
||||
</vector>
|
14
common/src/main/res/drawable/mine_white.xml
Executable file
|
@ -0,0 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M331.722,124.091l-33.743,-67.204l-83.901,0l-33.84,65.28l-80.22,0l-37.443,65.714l37.443,67.649l-37.443,66.12l37.42,67.746l80.243,0l39.239,65.717l75.084,0l37.161,-66.643l79.759,-0.019l37.942,-66.801l-40.501,-65.64l40.501,-68.129l-38.02,-63.79z"
|
||||
android:strokeWidth="0.02435089" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#666666"
|
||||
android:pathData="M360.853,255.692l-52.193,91.05l-104.8,0.177l-52.713,-90.616l52.081,-90.835l104.896,-0.386z" />
|
||||
</vector>
|
9
common/src/main/res/drawable/question_black.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF212121"
|
||||
android:pathData="M11,18h2v-2h-2v2zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
|
||||
</vector>
|
|
@ -1,116 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="Theme.AppCompat.DayNight">
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primary_dark</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar" parent="AppTheme">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Splash" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/splash</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomLightTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#9E9E9E</item>
|
||||
<item name="colorAccent">#D32F2F</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomLightTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#9E9E9E</item>
|
||||
<item name="colorAccent">#D32F2F</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomDarkTheme" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="colorPrimary">#212121</item>
|
||||
<item name="colorPrimaryDark">#212121</item>
|
||||
<item name="colorAccent">#FFFFFF</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomDarkTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="colorPrimary">#212121</item>
|
||||
<item name="colorPrimaryDark">#212121</item>
|
||||
<item name="colorAccent">#FFFFFF</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomGardenTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#53b529</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomGardenTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#53b529</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomMarineTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#03a9f4</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomMarineTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#03a9f4</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
</resources>
|
|
@ -32,6 +32,7 @@
|
|||
<string name="settings_large_areas">Use Large Areas</string>
|
||||
<string name="size">Size</string>
|
||||
<string name="system">System</string>
|
||||
<string name="amoled" translatable="false">AMOLED</string>
|
||||
<string name="rating">Feedback</string>
|
||||
<string name="support">Help supporting us!</string>
|
||||
<string name="support_description">It will allow us building new features and to keep our project active.</string>
|
||||
|
|
|
@ -4,86 +4,225 @@
|
|||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primary_dark</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="android:background">@color/primary</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar" parent="AppTheme">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Splash" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/splash</item>
|
||||
</style>
|
||||
|
||||
<style name="MyDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert">
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.DayNight.ActionBar" />
|
||||
|
||||
<style name="CustomLightTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#9E9E9E</item>
|
||||
<item name="colorAccent">#D32F2F</item>
|
||||
<item name="android:background">#FFFFFF</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomLightTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#9E9E9E</item>
|
||||
<item name="colorAccent">#D32F2F</item>
|
||||
<item name="android:background">#FFFFFF</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomDarkTheme" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="colorPrimary">#212121</item>
|
||||
<item name="colorPrimaryDark">#212121</item>
|
||||
<item name="colorAccent">#FFFFFF</item>
|
||||
<item name="android:background">#212121</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomDarkTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="colorPrimary">#212121</item>
|
||||
<item name="colorPrimaryDark">#212121</item>
|
||||
<item name="colorAccent">#FFFFFF</item>
|
||||
<item name="android:background">#212121</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomAmoledTheme" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="colorPrimary">#000000</item>
|
||||
<item name="colorPrimaryDark">#000000</item>
|
||||
<item name="android:windowBackground">#000000</item>
|
||||
<item name="colorAccent">#FFFFFF</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomAmoledTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="colorPrimary">#000000</item>
|
||||
<item name="colorPrimaryDark">#000000</item>
|
||||
<item name="android:windowBackground">#000000</item>
|
||||
<item name="colorAccent">#FFFFFF</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomGardenTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#19360d</item>
|
||||
<item name="colorPrimaryDark">#001000</item>
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#53b529</item>
|
||||
<item name="android:background">#FFFFFF</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomGardenTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#19360d</item>
|
||||
<item name="colorPrimaryDark">#001000</item>
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#53b529</item>
|
||||
<item name="android:background">#FFFFFF</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="CustomMarineTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#01579b</item>
|
||||
<item name="colorPrimaryDark">#002f6c</item>
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#03a9f4</item>
|
||||
<item name="android:background">#e1f5fe</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomMarineTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#01579b</item>
|
||||
<item name="colorPrimaryDark">#002f6c</item>
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#03a9f4</item>
|
||||
<item name="android:background">#e1f5fe</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomBlueGreyTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#42a5f5</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomBlueGreyTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#FFFFFF</item>
|
||||
<item name="colorAccent">#42a5f5</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomOrangeTheme" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="colorPrimary">#212121</item>
|
||||
<item name="colorPrimaryDark">#212121</item>
|
||||
<item name="colorAccent">#fb8c00</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomOrangeTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="colorPrimary">#212121</item>
|
||||
<item name="colorPrimaryDark">#212121</item>
|
||||
<item name="colorAccent">#fb8c00</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomPinkTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#9E9E9E</item>
|
||||
<item name="colorAccent">#f48fb1</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomPinkTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#9E9E9E</item>
|
||||
<item name="colorAccent">#f48fb1</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomPurpleTheme" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#9E9E9E</item>
|
||||
<item name="colorAccent">#9c27b0</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomPurpleTheme.NoActionBar" parent="ThemeOverlay.AppCompat.Light">
|
||||
<item name="colorPrimary">#FFFFFF</item>
|
||||
<item name="colorPrimaryDark">#9E9E9E</item>
|
||||
<item name="colorAccent">#9c27b0</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
|
@ -138,25 +138,31 @@ class GameControllerTest {
|
|||
@Test
|
||||
fun testShowWrongFlags() = runBlockingTest {
|
||||
withGameController { controller ->
|
||||
controller.field().first { !it.hasMine }
|
||||
.also { controller.fakeLongPress(it.id) }
|
||||
controller.field().first { !it.hasMine && it.isCovered }.run {
|
||||
controller.fakeLongPress(id)
|
||||
}
|
||||
|
||||
val wrongFlag = controller.field().first { !it.hasMine }
|
||||
controller.mines().first().run {
|
||||
controller.fakeLongPress(id)
|
||||
}
|
||||
|
||||
//val rightFlag = controller.mines().first().apply { controller.fakeLongPress(id) }
|
||||
controller.showWrongFlags()
|
||||
|
||||
val wrongFlag = controller.field().first { !it.hasMine && it.isCovered }
|
||||
val rightFlag = controller.mines().first()
|
||||
|
||||
assertTrue(wrongFlag.mistake)
|
||||
//assertFalse(rightFlag.mistake)
|
||||
assertFalse(rightFlag.mistake)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRevealAllEmptyAreas() = runBlockingTest {
|
||||
withGameController { controller ->
|
||||
val covered = controller.field().filter { it.isCovered }
|
||||
val covered = controller.field { it.isCovered }
|
||||
assertTrue(covered.isNotEmpty())
|
||||
controller.revealAllEmptyAreas()
|
||||
assertEquals(controller.field().filter { it.hasMine }, controller.field().filter { it.isCovered })
|
||||
assertEquals(controller.mines(), controller.field { it.isCovered })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,7 +193,14 @@ class GameControllerTest {
|
|||
assertEquals(20, controller.remainingMines())
|
||||
|
||||
repeat(20) { flagCount ->
|
||||
controller.field().filter { it.hasMine }.take(flagCount).forEach { controller.fakeLongPress(it.id) }
|
||||
controller.field()
|
||||
.filter { it.hasMine }
|
||||
.take(flagCount)
|
||||
.forEach {
|
||||
if (!it.mark.isFlag()) {
|
||||
controller.fakeLongPress(it.id)
|
||||
}
|
||||
}
|
||||
assertEquals("flagging $flagCount mines", 20 - flagCount, controller.remainingMines())
|
||||
}
|
||||
}
|
||||
|
@ -235,15 +248,16 @@ class GameControllerTest {
|
|||
withGameController { controller ->
|
||||
assertFalse(controller.checkVictory())
|
||||
|
||||
controller.field()
|
||||
.filter { it.hasMine }
|
||||
.forEach { controller.fakeLongPress(it.id) }
|
||||
controller.mines().forEach { controller.fakeLongPress(it.id) }
|
||||
assertFalse(controller.checkVictory())
|
||||
|
||||
controller.field().filterNot { it.hasMine }.forEach { controller.fakeSingleClick(it.id) }
|
||||
controller.field { !it.hasMine }.forEach { controller.fakeSingleClick(it.id) }
|
||||
assertTrue(controller.checkVictory())
|
||||
|
||||
controller.field().first { it.hasMine }.also { controller.fakeSingleClick(it.id) }
|
||||
controller.mines().first().run {
|
||||
controller.fakeSingleClick(id)
|
||||
controller.fakeSingleClick(id)
|
||||
}
|
||||
assertFalse(controller.checkVictory())
|
||||
}
|
||||
}
|
||||
|
@ -300,16 +314,17 @@ class GameControllerTest {
|
|||
updateGameControl(GameControl.fromControlType(ControlStyle.Standard))
|
||||
fakeSingleClick(14)
|
||||
assertFalse(at(14).isCovered)
|
||||
|
||||
field().filterNeighborsOf(at(14)).forEach {
|
||||
assertTrue(it.isCovered)
|
||||
}
|
||||
|
||||
field().filter { it.hasMine }.forEach {
|
||||
fakeLongPress(it.id)
|
||||
assertTrue(it.mark.isFlag())
|
||||
}
|
||||
mines().forEach { fakeLongPress(it.id) }
|
||||
|
||||
mines().forEach { assertTrue(it.mark.isFlag()) }
|
||||
|
||||
fakeLongPress(14)
|
||||
|
||||
field().filterNeighborsOf(at(14)).forEach {
|
||||
if (it.hasMine) {
|
||||
assertTrue(it.isCovered)
|
||||
|
@ -373,12 +388,16 @@ class GameControllerTest {
|
|||
updateGameControl(GameControl.fromControlType(ControlStyle.FastFlag))
|
||||
fakeLongPress(14)
|
||||
assertFalse(at(14).isCovered)
|
||||
|
||||
field().filterNeighborsOf(at(14)).forEach {
|
||||
assertTrue(it.isCovered)
|
||||
}
|
||||
|
||||
field().filter { it.hasMine }.forEach {
|
||||
mines().forEach {
|
||||
fakeSingleClick(it.id)
|
||||
}
|
||||
|
||||
mines().forEach {
|
||||
assertTrue(it.mark.isFlag())
|
||||
}
|
||||
|
||||
|
@ -456,9 +475,9 @@ class GameControllerTest {
|
|||
assertTrue(it.isCovered)
|
||||
}
|
||||
|
||||
field().filter { it.hasMine }
|
||||
.onEach { fakeSingleClick(it.id) }
|
||||
.onEach { assertTrue(it.mark.isFlag()) }
|
||||
mines().forEach { fakeSingleClick(it.id) }
|
||||
|
||||
mines().forEach { assertTrue(it.mark.isFlag()) }
|
||||
|
||||
fakeDoubleClick(14)
|
||||
field().filterNeighborsOf(at(14)).forEach {
|
||||
|
|
|
@ -73,6 +73,7 @@ class MinefieldFactoryTest {
|
|||
fun testFromDifficultyPresetStandard() {
|
||||
val dimensionRepository: IDimensionRepository = mock {
|
||||
on { areaSize() } doReturn 10.0f
|
||||
on { defaultAreaSize() } doReturn 10.0f
|
||||
on { actionBarSize() } doReturn 10
|
||||
on { displaySize() } doReturn Size(500, 1000)
|
||||
}
|
||||
|
@ -84,7 +85,7 @@ class MinefieldFactoryTest {
|
|||
).run {
|
||||
assertEquals(49, width)
|
||||
assertEquals(96, height)
|
||||
assertEquals(950, mines)
|
||||
assertEquals(940, mines)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package dev.lucasnlm.antimine.common.level.logic
|
||||
|
||||
import dev.lucasnlm.antimine.common.level.models.Area
|
||||
import dev.lucasnlm.antimine.common.level.models.Mark
|
||||
import dev.lucasnlm.antimine.common.level.models.Minefield
|
||||
import org.junit.Assert.assertEquals
|
||||
|
@ -13,138 +12,162 @@ class MinefieldHandlerTest {
|
|||
private fun handleMinefield(
|
||||
useQuestionMark: Boolean = false,
|
||||
useSafeZone: Boolean = false,
|
||||
block: (MinefieldHandler, MutableList<Area>) -> Unit
|
||||
block: (MinefieldHandler) -> Unit
|
||||
) {
|
||||
val creator = MinefieldCreator(Minefield(4, 4, 9), Random(200))
|
||||
val minefield = creator.create(10, useSafeZone).toMutableList()
|
||||
val minefieldHandler = MinefieldHandler(minefield, useQuestionMark)
|
||||
block(minefieldHandler, minefield)
|
||||
block(minefieldHandler)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOpenArea() {
|
||||
handleMinefield { handler, minefield ->
|
||||
assertTrue(minefield[3].isCovered)
|
||||
handleMinefield { handler ->
|
||||
assertTrue(handler.result()[3].isCovered)
|
||||
handler.openAt(3, false, openNeighbors = false)
|
||||
assertFalse(minefield[3].isCovered)
|
||||
assertEquals(Mark.None, minefield[3].mark)
|
||||
assertFalse(handler.result()[3].isCovered)
|
||||
assertEquals(Mark.None, handler.result()[3].mark)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOpenAreaWithSafeZone() {
|
||||
handleMinefield(useSafeZone = true) { handler, minefield ->
|
||||
assertTrue(minefield[3].isCovered)
|
||||
handleMinefield(useSafeZone = true) { handler ->
|
||||
assertTrue(handler.result()[3].isCovered)
|
||||
handler.openAt(3, false, openNeighbors = false)
|
||||
assertFalse(minefield[3].isCovered)
|
||||
assertEquals(Mark.None, minefield[3].mark)
|
||||
assertFalse(handler.result()[3].isCovered)
|
||||
assertEquals(Mark.None, handler.result()[3].mark)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTurnOffHighlight() {
|
||||
handleMinefield { handler, minefield ->
|
||||
minefield[3] = minefield[3].copy(highlighted = true)
|
||||
handleMinefield { handler ->
|
||||
handler.highlightAt(3)
|
||||
handler.turnOffAllHighlighted()
|
||||
assertFalse(minefield[3].highlighted)
|
||||
assertFalse(handler.result()[3].highlighted)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveMark() {
|
||||
handleMinefield { handler, minefield ->
|
||||
minefield[3] = minefield[3].copy(mark = Mark.Flag)
|
||||
handleMinefield { handler ->
|
||||
handler.switchMarkAt(3)
|
||||
|
||||
handler.removeMarkAt(3)
|
||||
assertTrue(minefield[3].mark == Mark.PurposefulNone)
|
||||
assertTrue(minefield[3].mark.isNone())
|
||||
assertTrue(handler.result()[3].mark == Mark.PurposefulNone)
|
||||
assertTrue(handler.result()[3].mark.isNone())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSwitchMarkWithoutQuestionMark() {
|
||||
handleMinefield { handler, minefield ->
|
||||
assertTrue(minefield[3].mark.isNone())
|
||||
handleMinefield { handler ->
|
||||
assertTrue(handler.result()[3].mark.isNone())
|
||||
|
||||
handler.switchMarkAt(3)
|
||||
assertTrue(minefield[3].mark.isFlag())
|
||||
assertTrue(handler.result()[3].mark.isFlag())
|
||||
|
||||
handler.switchMarkAt(3)
|
||||
assertTrue(minefield[3].mark.isNone())
|
||||
assertTrue(handler.result()[3].mark.isNone())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSwitchMarkWithQuestionMark() {
|
||||
handleMinefield(useQuestionMark = true) { handler, minefield ->
|
||||
assertTrue(minefield[3].mark.isNone())
|
||||
handleMinefield(useQuestionMark = true) { handler ->
|
||||
assertTrue(handler.result()[3].mark.isNone())
|
||||
|
||||
handler.switchMarkAt(3)
|
||||
assertTrue(minefield[3].mark.isFlag())
|
||||
assertTrue(handler.result()[3].mark.isFlag())
|
||||
|
||||
handler.switchMarkAt(3)
|
||||
assertTrue(minefield[3].mark.isQuestion())
|
||||
assertTrue(handler.result()[3].mark.isQuestion())
|
||||
|
||||
handler.switchMarkAt(3)
|
||||
assertTrue(minefield[3].mark.isNone())
|
||||
assertTrue(handler.result()[3].mark.isNone())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHighlight() {
|
||||
handleMinefield(useQuestionMark = true) { handler, minefield ->
|
||||
assertEquals(0, minefield.count { it.highlighted })
|
||||
handleMinefield(useQuestionMark = true) { handler ->
|
||||
assertEquals(0, handler.result().count { it.highlighted })
|
||||
|
||||
// Before open
|
||||
handler.highlightAt(5)
|
||||
assertEquals(0, minefield.count { it.highlighted })
|
||||
assertEquals(0, handler.result().count { it.highlighted })
|
||||
|
||||
// After Open
|
||||
handler.openAt(5, false, openNeighbors = false)
|
||||
val target = minefield.first { it.minesAround != 0 }
|
||||
val target = handler.result().first { it.minesAround != 0 }
|
||||
handler.highlightAt(target.id)
|
||||
assertEquals(5, minefield.count { it.highlighted })
|
||||
assertEquals(listOf(0, 1, 4, 8, 9), minefield.filter { it.highlighted }.map { it.id }.toList())
|
||||
assertEquals(5, handler.result().count { it.highlighted })
|
||||
assertEquals(listOf(0, 1, 4, 8, 9), handler.result().filter { it.highlighted }.map { it.id }.toList())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOpenNeighborsClosedArea() {
|
||||
handleMinefield { handler, minefield ->
|
||||
handleMinefield { handler ->
|
||||
handler.openOrFlagNeighborsOf(3)
|
||||
assertEquals(0, minefield.count { !it.isCovered })
|
||||
assertEquals(0, handler.result().count { !it.isCovered })
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOpenNeighbors() {
|
||||
handleMinefield { handler, minefield ->
|
||||
handleMinefield { handler ->
|
||||
handler.openAt(5, false, openNeighbors = true)
|
||||
handler.openOrFlagNeighborsOf(5)
|
||||
assertEquals(9, minefield.count { !it.isCovered })
|
||||
assertEquals(9, handler.result().count { !it.isCovered })
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOpenNeighborsWithFlags() {
|
||||
handleMinefield { handler, minefield ->
|
||||
handleMinefield { handler ->
|
||||
handler.openAt(5, false, openNeighbors = true)
|
||||
val neighbors = minefield.filterNeighborsOf(minefield.first { it.id == 5 })
|
||||
neighbors.filter { it.hasMine }.forEach { handler.switchMarkAt(it.id) }
|
||||
|
||||
handler.result()
|
||||
.filterNeighborsOf(handler.result().first { it.id == 5 })
|
||||
.filter { it.hasMine }
|
||||
.forEach { handler.switchMarkAt(it.id) }
|
||||
|
||||
handler.openOrFlagNeighborsOf(5)
|
||||
assertEquals(4, minefield.count { !it.isCovered })
|
||||
assertEquals(3, neighbors.count { !it.isCovered })
|
||||
|
||||
val remainCovered =
|
||||
handler.result().count { !it.isCovered }
|
||||
val remainCoveredNeighbors =
|
||||
handler.result().filterNeighborsOf(handler.result().first { it.id == 5 }).count { !it.isCovered }
|
||||
|
||||
assertEquals(4, remainCovered)
|
||||
assertEquals(3, remainCoveredNeighbors)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOpenNeighborsWithQuestionMarks() {
|
||||
handleMinefield(useQuestionMark = true) { handler, minefield ->
|
||||
handler.openAt(5, false, openNeighbors = true)
|
||||
val neighbors = minefield.filterNeighborsOf(minefield.first { it.id == 5 })
|
||||
neighbors
|
||||
handleMinefield(useQuestionMark = true) { handler ->
|
||||
handler.openAt(5, false, openNeighbors = false)
|
||||
|
||||
handler.result()
|
||||
.filterNeighborsOf(handler.result().first { it.id == 5 })
|
||||
.filter { it.hasMine }
|
||||
.forEach {
|
||||
handler.switchMarkAt(it.id)
|
||||
handler.switchMarkAt(it.id)
|
||||
}
|
||||
|
||||
handler.openOrFlagNeighborsOf(5)
|
||||
assertEquals(4, minefield.count { !it.isCovered })
|
||||
assertEquals(3, neighbors.count { !it.isCovered })
|
||||
|
||||
val remainCovered =
|
||||
handler.result().count { !it.isCovered }
|
||||
val remainCoveredNeighbors =
|
||||
handler.result().filterNeighborsOf(handler.result().first { it.id == 5 }).count { !it.isCovered }
|
||||
|
||||
assertEquals(4, remainCovered)
|
||||
assertEquals(3, remainCoveredNeighbors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package dev.lucasnlm.antimine.common.level.solver
|
|||
|
||||
import dev.lucasnlm.antimine.common.level.logic.MinefieldCreator
|
||||
import dev.lucasnlm.antimine.common.level.logic.MinefieldHandler
|
||||
import dev.lucasnlm.antimine.common.level.models.Area
|
||||
import dev.lucasnlm.antimine.common.level.models.Minefield
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
|
@ -11,7 +10,7 @@ import org.junit.Test
|
|||
import kotlin.random.Random
|
||||
|
||||
class BruteForceSolverTest {
|
||||
private fun handleMinefield(block: (MinefieldHandler, MutableList<Area>) -> Unit) {
|
||||
private fun handleMinefield(block: (MinefieldHandler) -> Unit) {
|
||||
val creator = MinefieldCreator(
|
||||
Minefield(9, 9, 12),
|
||||
Random(200)
|
||||
|
@ -19,21 +18,21 @@ class BruteForceSolverTest {
|
|||
val minefield = creator.create(40, true).toMutableList()
|
||||
val minefieldHandler =
|
||||
MinefieldHandler(minefield, false)
|
||||
block(minefieldHandler, minefield)
|
||||
block(minefieldHandler)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isSolvable() {
|
||||
handleMinefield { handler, minefield ->
|
||||
handler.openAt(40, passive = false, openNeighbors = false)
|
||||
handleMinefield { handler ->
|
||||
handler.openAt(40, passive = false, openNeighbors = true)
|
||||
val bruteForceSolver = BruteForceSolver()
|
||||
assertTrue(bruteForceSolver.trySolve(minefield.toMutableList()))
|
||||
assertTrue(bruteForceSolver.trySolve(handler.result().toMutableList()))
|
||||
}
|
||||
|
||||
handleMinefield { handler, minefield ->
|
||||
handleMinefield { handler ->
|
||||
handler.openAt(0, passive = false, openNeighbors = false)
|
||||
val bruteForceSolver = BruteForceSolver()
|
||||
assertFalse(bruteForceSolver.trySolve(minefield.toMutableList()))
|
||||
assertFalse(bruteForceSolver.trySolve(handler.result().toMutableList()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package dev.lucasnlm.antimine.common.level.solver
|
|||
|
||||
import dev.lucasnlm.antimine.common.level.logic.MinefieldCreator
|
||||
import dev.lucasnlm.antimine.common.level.logic.MinefieldHandler
|
||||
import dev.lucasnlm.antimine.common.level.models.Area
|
||||
import dev.lucasnlm.antimine.common.level.models.Minefield
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
|
@ -11,41 +10,40 @@ import java.lang.Thread.sleep
|
|||
import kotlin.random.Random
|
||||
|
||||
class LimitedBruteForceSolverTest {
|
||||
private fun handleMinefield(block: (MinefieldHandler, MutableList<Area>) -> Unit) {
|
||||
private fun handleMinefield(block: (MinefieldHandler) -> Unit) {
|
||||
val creator = MinefieldCreator(
|
||||
Minefield(9, 9, 12),
|
||||
Random(200)
|
||||
)
|
||||
val minefield = creator.create(40, true).toMutableList()
|
||||
val minefieldHandler =
|
||||
MinefieldHandler(minefield, false)
|
||||
block(minefieldHandler, minefield)
|
||||
val minefieldHandler = MinefieldHandler(minefield, false)
|
||||
block(minefieldHandler)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isSolvable() {
|
||||
handleMinefield { handler, minefield ->
|
||||
handler.openAt(40, passive = false, openNeighbors = false)
|
||||
handleMinefield { handler ->
|
||||
handler.openAt(40, passive = false, openNeighbors = true)
|
||||
val bruteForceSolver = LimitedBruteForceSolver()
|
||||
assertTrue(bruteForceSolver.trySolve(minefield.toMutableList()))
|
||||
assertTrue(bruteForceSolver.trySolve(handler.result().toMutableList()))
|
||||
}
|
||||
|
||||
handleMinefield { handler, minefield ->
|
||||
handler.openAt(0, passive = false, openNeighbors = false)
|
||||
handleMinefield { handler ->
|
||||
handler.openAt(0, passive = false, openNeighbors = true)
|
||||
val bruteForceSolver = LimitedBruteForceSolver()
|
||||
assertFalse(bruteForceSolver.trySolve(minefield.toMutableList()))
|
||||
assertFalse(bruteForceSolver.trySolve(handler.result().toMutableList()))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldntKeepTryingAfterTimeout() {
|
||||
handleMinefield { handler, _ ->
|
||||
handleMinefield { handler ->
|
||||
handler.openAt(40, passive = false, openNeighbors = false)
|
||||
val bruteForceSolver = LimitedBruteForceSolver(1000L)
|
||||
assertTrue(bruteForceSolver.keepTrying())
|
||||
}
|
||||
|
||||
handleMinefield { handler, _ ->
|
||||
handleMinefield { handler ->
|
||||
handler.openAt(0, passive = false, openNeighbors = false)
|
||||
val bruteForceSolver = LimitedBruteForceSolver(50)
|
||||
sleep(100)
|
||||
|
|
|
@ -37,7 +37,7 @@ class PreferencesRepositoryTest {
|
|||
@Test
|
||||
fun testProgressValue() {
|
||||
val preferenceManager = TestPreferenceManager()
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager)
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager, 400)
|
||||
|
||||
assertEquals(0, preferencesRepository.getProgressiveValue())
|
||||
|
||||
|
@ -63,7 +63,7 @@ class PreferencesRepositoryTest {
|
|||
preferenceManager.putBoolean("preference_double_click_open", true)
|
||||
assertTrue(preferenceManager.values["preference_double_click_open"] as Boolean)
|
||||
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager)
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager, 400)
|
||||
|
||||
assertTrue(preferenceManager.values["preference_double_click_open"] == null)
|
||||
assertEquals(1, preferenceManager.values["preference_control_style"])
|
||||
|
@ -76,7 +76,7 @@ class PreferencesRepositoryTest {
|
|||
preferenceManager.putBoolean("preference_double_click_open", false)
|
||||
assertFalse(preferenceManager.values["preference_double_click_open"] as Boolean)
|
||||
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager)
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager, 400)
|
||||
|
||||
assertTrue(preferenceManager.values["preference_double_click_open"] == null)
|
||||
assertFalse(preferencesRepository.getBoolean("preference_double_click_open", false))
|
||||
|
@ -88,7 +88,7 @@ class PreferencesRepositoryTest {
|
|||
preferenceManager.putBoolean("preference_large_area", true)
|
||||
assertTrue(preferenceManager.values["preference_large_area"] as Boolean)
|
||||
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager)
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager, 400)
|
||||
|
||||
assertTrue(preferenceManager.values["preference_large_area"] == null)
|
||||
assertEquals(63, preferencesRepository.getInt("preference_area_size", -1))
|
||||
|
@ -97,7 +97,7 @@ class PreferencesRepositoryTest {
|
|||
@Test
|
||||
fun testMigrationLargeAreaOff() {
|
||||
val preferenceManager = TestPreferenceManager()
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager)
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager, 400)
|
||||
|
||||
assertTrue(preferenceManager.values["preference_large_area"] == null)
|
||||
assertEquals(50, preferencesRepository.getInt("preference_area_size", -1))
|
||||
|
@ -109,7 +109,7 @@ class PreferencesRepositoryTest {
|
|||
preferenceManager.putBoolean("preference_large_area", false)
|
||||
assertEquals(false, preferenceManager.values["preference_large_area"] as Boolean)
|
||||
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager)
|
||||
val preferencesRepository = PreferencesRepository(preferenceManager, 400)
|
||||
|
||||
assertTrue(preferenceManager.values["preference_large_area"] == null)
|
||||
assertEquals(50, preferencesRepository.getInt("preference_area_size", -1))
|
||||
|
|
2
external/build.gradle
vendored
|
@ -7,7 +7,7 @@ android {
|
|||
compileSdkVersion 30
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
|
|
|
@ -8,7 +8,7 @@ android {
|
|||
defaultConfig {
|
||||
versionCode 800051 // MMmmPPv
|
||||
versionName '8.0.5'
|
||||
minSdkVersion 16
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ android {
|
|||
defaultConfig {
|
||||
versionCode 800051
|
||||
versionName '8.0.5'
|
||||
minSdkVersion 16
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
}
|
||||
|
||||
|
|
|
@ -63,12 +63,7 @@ class WatchLevelFragment : CommonLevelFragment(R.layout.fragment_level) {
|
|||
}
|
||||
}
|
||||
)
|
||||
fieldRefresh.observe(
|
||||
viewLifecycleOwner,
|
||||
Observer {
|
||||
areaAdapter.notifyItemChanged(it)
|
||||
}
|
||||
)
|
||||
|
||||
eventObserver.observe(
|
||||
viewLifecycleOwner,
|
||||
Observer {
|
||||
|
|