Skip to content

Commit 3fdcdff

Browse files
authored
Merge pull request #471 from lucasnlm/fix-crash
Improve wear app
2 parents 253799f + a34a329 commit 3fdcdff

File tree

61 files changed

+510
-164
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+510
-164
lines changed

about/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ dependencies {
4848
// AndroidX
4949
implementation 'androidx.appcompat:appcompat:1.6.1'
5050
implementation 'androidx.activity:activity-ktx:1.8.0'
51-
implementation 'androidx.fragment:fragment-ktx:1.6.1'
51+
implementation 'androidx.fragment:fragment-ktx:1.6.2'
5252

5353
// RecyclerView
54-
implementation 'androidx.recyclerview:recyclerview:1.3.1'
54+
implementation 'androidx.recyclerview:recyclerview:1.3.2'
5555

5656
// Constraint
5757
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

about/src/main/java/dev/lucasnlm/antimine/about/views/AboutInfoFragment.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel
2424
import dev.lucasnlm.antimine.i18n.R as i18n
2525

2626
class AboutInfoFragment : Fragment() {
27-
private lateinit var binding: FragmentAboutInfoBinding
2827
private val aboutViewModel: AboutViewModel by sharedViewModel()
2928
private val audioManager: GameAudioManager by inject()
3029
private val analyticsManager: AnalyticsManager by inject()
3130
private val unknownVersionName = "?.?.?"
3231

32+
private lateinit var binding: FragmentAboutInfoBinding
33+
3334
private fun PackageManager.getPackageInfoCompat(
3435
packageName: String,
3536
flags: Int = 0,

app/build.gradle

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ android {
88

99
defaultConfig {
1010
// versionCode and versionName must be hardcoded to support F-droid
11-
versionCode 1705061
12-
versionName '17.5.6'
11+
versionCode 1705071
12+
versionName '17.5.7'
1313
minSdk 21
1414
targetSdk 34
1515
compileSdk 34
@@ -22,10 +22,10 @@ android {
2222
signingConfigs {
2323
release {
2424
if (System.getenv('IS_RELEASE_BUILD')) {
25-
storeFile file(System.getenv('KEYSTORE'))
26-
keyAlias System.getenv('KEY_ALIAS')
27-
storePassword System.getenv('KEY_STORE_PASSWORD')
28-
keyPassword System.getenv('KEY_PASSWORD')
25+
storeFile file('../keystore')
26+
keyAlias System.getenv('BITRISEIO_ANDROID_KEYSTORE_ALIAS')
27+
storePassword System.getenv('BITRISEIO_ANDROID_KEYSTORE_PASSWORD')
28+
keyPassword System.getenv('BITRISEIO_ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD')
2929
}
3030
}
3131
}
@@ -77,7 +77,7 @@ android {
7777
}
7878

7979
googleInstant {
80-
versionCode 160
80+
versionCode 161
8181
dimension 'version'
8282
applicationId 'dev.lucasnlm.antimine'
8383
versionNameSuffix ' I'
@@ -122,10 +122,10 @@ dependencies {
122122
// AndroidX
123123
implementation 'androidx.appcompat:appcompat:1.6.1'
124124
implementation 'androidx.preference:preference-ktx:1.2.1'
125-
implementation 'androidx.recyclerview:recyclerview:1.3.1'
125+
implementation 'androidx.recyclerview:recyclerview:1.3.2'
126126
implementation 'androidx.multidex:multidex:2.0.1'
127127
implementation 'androidx.activity:activity-ktx:1.8.0'
128-
implementation 'androidx.fragment:fragment-ktx:1.6.1'
128+
implementation 'androidx.fragment:fragment-ktx:1.6.2'
129129

130130
// Lifecycle
131131
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
@@ -158,7 +158,7 @@ dependencies {
158158
testImplementation 'androidx.test:rules:1.5.0'
159159
testImplementation 'androidx.test:runner:1.5.2'
160160
testImplementation 'androidx.test.espresso:espresso-core:3.5.1'
161-
testImplementation 'androidx.fragment:fragment-testing:1.6.1'
161+
testImplementation 'androidx.fragment:fragment-testing:1.6.2'
162162
testImplementation 'org.robolectric:robolectric:4.5.1'
163163
testImplementation 'androidx.test.ext:junit:1.1.5'
164164
testImplementation 'io.mockk:mockk:1.13.5'
@@ -194,6 +194,13 @@ if (System.getenv('IS_GOOGLE_BUILD') == null) {
194194
enabled = false
195195
}
196196
}
197+
198+
project.tasks.names.findAll { it.contains("Bugsnag") }
199+
.forEach { taskName ->
200+
project.tasks.named(taskName).configure {
201+
enabled = false
202+
}
203+
}
197204
}
198205
}
199206
}

app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,11 @@ class GameActivity :
377377
}
378378
is GameEvent.VictoryDialog -> {
379379
if (preferencesRepository.showWindowsWhenFinishGame()) {
380-
withContext(Dispatchers.Main) {
381-
showKonfettiView()
380+
val duration = gameViewModel.singleState().duration
381+
if (duration > 5) {
382+
withContext(Dispatchers.Main) {
383+
showKonfettiView()
384+
}
382385
}
383386

384387
lifecycleScope.launch {

app/src/main/java/dev/lucasnlm/antimine/custom/CustomLevelDialogFragment.kt

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ import android.content.DialogInterface
55
import android.os.Bundle
66
import android.view.LayoutInflater
77
import android.view.View
8+
import android.view.animation.AnimationUtils
89
import androidx.appcompat.app.AppCompatDialogFragment
10+
import androidx.core.widget.doAfterTextChanged
911
import com.google.android.material.dialog.MaterialAlertDialogBuilder
12+
import com.google.android.material.textfield.TextInputEditText
13+
import dev.lucasnlm.antimine.R
1014
import dev.lucasnlm.antimine.core.models.Difficulty
1115
import dev.lucasnlm.antimine.custom.viewmodel.CreateGameViewModel
1216
import dev.lucasnlm.antimine.custom.viewmodel.CustomEvent
@@ -47,12 +51,68 @@ class CustomLevelDialogFragment : AppCompatDialogFragment() {
4751
mapHeight.setText(state.height.toString())
4852
mapMines.setText(state.mines.toString())
4953
seed.setText("")
54+
55+
mapWidth.checkLimit(MIN_WIDTH, MAX_WIDTH)
56+
mapHeight.checkLimit(MIN_HEIGHT, MAX_HEIGHT)
57+
mapMines.checkProportionOnChange()
5058
}
5159
}
5260

5361
return binding.root
5462
}
5563

64+
private fun TextInputEditText.checkProportion() {
65+
val width = binding.mapWidth.text.toString().toIntOrNull()
66+
val height = binding.mapHeight.text.toString().toIntOrNull()
67+
val current = text.toString().toIntOrNull()
68+
error =
69+
if (current != null && width != null && height != null) {
70+
val minMines = (width * height * 0.5 - MIN_SAFE_AREA).toInt().coerceAtLeast(1)
71+
if (current <= minMines) {
72+
null
73+
} else {
74+
val maxProportion = width * height * 0.75
75+
if (current >= maxProportion) {
76+
getString(i18n.string.proportion_too_high)
77+
} else {
78+
null
79+
}
80+
}
81+
} else {
82+
null
83+
}
84+
}
85+
86+
private fun TextInputEditText.checkProportionOnChange() {
87+
doAfterTextChanged {
88+
checkProportion()
89+
}
90+
}
91+
92+
private fun TextInputEditText.checkLimit(
93+
min: Int,
94+
max: Int,
95+
) {
96+
doAfterTextChanged {
97+
if (it?.isNotBlank() == true) {
98+
val current = text.toString().toIntOrNull()
99+
if (current != null) {
100+
if (current > max) {
101+
error = getString(i18n.string.value_limit_max, max)
102+
} else if (current < min) {
103+
error = getString(i18n.string.value_limit_min, min)
104+
}
105+
} else {
106+
error = null
107+
}
108+
} else {
109+
error = null
110+
}
111+
112+
binding.mapMines.checkProportion()
113+
}
114+
}
115+
56116
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
57117
return MaterialAlertDialogBuilder(requireContext()).apply {
58118
setTitle(i18n.string.new_game)
@@ -67,6 +127,56 @@ class CustomLevelDialogFragment : AppCompatDialogFragment() {
67127
}.create()
68128
}
69129

130+
private fun checkLimitFeedbacks(): Boolean {
131+
val wantedWidth = binding.mapWidth.text.toString().toIntOrNull()
132+
var allValid = true
133+
if (wantedWidth == null) {
134+
binding.mapWidth.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
135+
allValid = false
136+
} else if (wantedWidth >= MAX_WIDTH) {
137+
binding.mapWidth.setText(MAX_WIDTH.toString())
138+
binding.mapWidth.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
139+
allValid = false
140+
} else if (wantedWidth <= MIN_WIDTH) {
141+
binding.mapWidth.setText(MIN_WIDTH.toString())
142+
binding.mapWidth.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
143+
allValid = false
144+
}
145+
146+
val wantedHeight = binding.mapHeight.text.toString().toIntOrNull()
147+
if (wantedHeight == null) {
148+
binding.mapHeight.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
149+
allValid = false
150+
} else if (wantedHeight >= MAX_HEIGHT) {
151+
binding.mapHeight.setText(MAX_HEIGHT.toString())
152+
binding.mapHeight.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
153+
allValid = false
154+
} else if (wantedHeight <= MIN_HEIGHT) {
155+
binding.mapHeight.setText(MIN_HEIGHT.toString())
156+
binding.mapHeight.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
157+
allValid = false
158+
}
159+
160+
if (allValid && wantedWidth != null && wantedHeight != null) {
161+
val wantedMines = binding.mapMines.text.toString().toIntOrNull()
162+
val maxMines = wantedWidth * wantedHeight - MIN_SAFE_AREA
163+
if (wantedMines == null) {
164+
binding.mapMines.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
165+
allValid = false
166+
} else if (wantedMines >= maxMines) {
167+
binding.mapMines.setText((wantedWidth * wantedHeight - MIN_SAFE_AREA).toString())
168+
binding.mapMines.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
169+
allValid = false
170+
} else if (wantedMines <= MIN_MINES) {
171+
binding.mapMines.setText(MIN_MINES.toString())
172+
binding.mapMines.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fast_shake))
173+
allValid = false
174+
}
175+
}
176+
177+
return allValid
178+
}
179+
70180
override fun onDismiss(dialog: DialogInterface) {
71181
if (activity is DialogInterface.OnDismissListener) {
72182
(activity as DialogInterface.OnDismissListener).onDismiss(dialog)
@@ -79,8 +189,8 @@ class CustomLevelDialogFragment : AppCompatDialogFragment() {
79189
const val MIN_HEIGHT = 5
80190
const val MIN_MINES = 3
81191
const val MIN_SAFE_AREA = 9
82-
const val MAX_WIDTH = 50
83-
const val MAX_HEIGHT = 50
192+
const val MAX_WIDTH = 100
193+
const val MAX_HEIGHT = 100
84194

85195
private fun filterInput(
86196
target: String,

app/src/main/java/dev/lucasnlm/antimine/di/AppModule.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import dev.lucasnlm.antimine.core.analytics.ProdAnalyticsManager
88
import dev.lucasnlm.antimine.core.cloud.CloudSaveManager
99
import dev.lucasnlm.antimine.core.haptic.HapticFeedbackManager
1010
import dev.lucasnlm.antimine.core.haptic.HapticFeedbackManagerImpl
11+
import dev.lucasnlm.antimine.core.repository.DimensionRepository
12+
import dev.lucasnlm.antimine.core.repository.DimensionRepositoryImpl
1113
import dev.lucasnlm.antimine.l10n.GameLocaleManager
1214
import dev.lucasnlm.antimine.l10n.GameLocaleManagerImpl
1315
import dev.lucasnlm.antimine.support.AppVersionManagerImpl
@@ -25,6 +27,8 @@ val AppModule =
2527
module {
2628
factory { CoroutineScope(Dispatchers.Main + SupervisorJob()) }
2729

30+
single { DimensionRepositoryImpl(get()) } bind DimensionRepository::class
31+
2832
single { IapHandler(get(), get(), get()) }
2933

3034
single {

app/src/main/java/dev/lucasnlm/antimine/main/MainActivity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import dev.lucasnlm.antimine.common.io.models.SaveStatus
2222
import dev.lucasnlm.antimine.common.level.repository.MinefieldRepository
2323
import dev.lucasnlm.antimine.common.level.repository.SavesRepository
2424
import dev.lucasnlm.antimine.control.ControlActivity
25+
import dev.lucasnlm.antimine.core.ActivityExt.compatOverridePendingTransition
2526
import dev.lucasnlm.antimine.core.audio.GameAudioManager
2627
import dev.lucasnlm.antimine.core.models.Analytics
2728
import dev.lucasnlm.antimine.core.models.Difficulty

app/src/main/java/dev/lucasnlm/antimine/preferences/PreferencesActivity.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@ class PreferencesActivity :
3535
private val settingsBackupManager: SettingsBackupManager by lazy {
3636
SettingsBackupManager(applicationContext)
3737
}
38+
private val binding: ActivityPreferencesBinding by lazy {
39+
ActivityPreferencesBinding.inflate(layoutInflater)
40+
}
3841

3942
private lateinit var exportResultLauncher: ActivityResultLauncher<Intent>
4043
private lateinit var importResultLauncher: ActivityResultLauncher<Intent>
41-
private lateinit var binding: ActivityPreferencesBinding
4244

4345
private val preferenceManager by lazy {
4446
PreferenceManager.getDefaultSharedPreferences(applicationContext)
@@ -61,7 +63,6 @@ class PreferencesActivity :
6163
override fun onCreate(savedInstanceState: Bundle?) {
6264
super.onCreate(savedInstanceState)
6365

64-
binding = ActivityPreferencesBinding.inflate(layoutInflater)
6566
setContentView(binding.root)
6667

6768
exportResultLauncher =
@@ -205,6 +206,11 @@ class PreferencesActivity :
205206
onChangeValue = { preferencesRepository.setDimNumbers(it) },
206207
)
207208

209+
binding.immersiveMode.bindItem(
210+
initialValue = preferencesRepository.useImmersiveMode(),
211+
onChangeValue = { preferencesRepository.setImmersiveMode(it) },
212+
)
213+
208214
if (playGamesManager.hasGooglePlayGames()) {
209215
binding.playGames.bindItem(
210216
initialValue = preferencesRepository.keepRequestPlayGames(),

app/src/main/res/layout/activity_preferences.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@
103103
android:layout_height="wrap_content"
104104
android:paddingVertical="16dp"
105105
android:text="@string/google_play_games" />
106+
107+
<com.google.android.material.materialswitch.MaterialSwitch
108+
android:id="@+id/immersiveMode"
109+
android:layout_width="match_parent"
110+
android:layout_height="wrap_content"
111+
android:paddingVertical="16dp"
112+
android:text="@string/immersive_mode" />
106113
</LinearLayout>
107114
</com.google.android.material.card.MaterialCardView>
108115

app/src/main/res/layout/game_over_dialog.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
android:layout_width="wrap_content"
6666
android:layout_height="wrap_content"
6767
android:background="?selectableItemBackgroundBorderless"
68+
android:tooltipText="@string/close"
6869
android:contentDescription="@string/cancel"
6970
android:importantForAccessibility="no"
7071
android:padding="8dp"
@@ -78,9 +79,11 @@
7879
style="@style/Widget.Material3.Button.IconButton"
7980
android:layout_width="wrap_content"
8081
android:layout_height="wrap_content"
82+
android:background="?selectableItemBackgroundBorderless"
8183
android:contentDescription="@string/settings"
8284
android:importantForAccessibility="no"
8385
android:padding="8dp"
86+
android:tooltipText="@string/settings"
8487
app:icon="@drawable/settings"
8588
app:iconTint="?colorOnBackground"
8689
app:layout_constraintStart_toStartOf="parent"

app/src/main/res/layout/win_dialog.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
android:layout_width="wrap_content"
8282
android:layout_height="wrap_content"
8383
android:background="?selectableItemBackgroundBorderless"
84+
android:tooltipText="@string/close"
8485
android:contentDescription="@string/cancel"
8586
android:importantForAccessibility="no"
8687
android:padding="8dp"
@@ -95,6 +96,7 @@
9596
android:layout_width="wrap_content"
9697
android:layout_height="wrap_content"
9798
android:background="?selectableItemBackgroundBorderless"
99+
android:tooltipText="@string/settings"
98100
android:contentDescription="@string/settings"
99101
android:importantForAccessibility="no"
100102
android:padding="8dp"

app/src/test/java/dev/lucasnlm/antimine/di/TestCommonModule.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import dev.lucasnlm.antimine.ui.model.AppSkin
99
import dev.lucasnlm.antimine.ui.model.AppTheme
1010
import dev.lucasnlm.antimine.ui.repository.Skins
1111
import dev.lucasnlm.antimine.ui.repository.ThemeRepository
12+
import dev.lucasnlm.antimine.ui.repository.Themes.darkTheme
1213
import dev.lucasnlm.antimine.ui.repository.Themes.lightTheme
1314
import io.mockk.mockk
1415
import org.koin.dsl.bind
@@ -34,6 +35,8 @@ val TestCommonModule =
3435

3536
override fun getAllThemes(): List<AppTheme> = listOf(lightTheme())
3637

38+
override fun getAllDarkThemes(): List<AppTheme> = listOf(darkTheme())
39+
3740
override fun getAllSkins(): List<AppSkin> = Skins.getAllSkins()
3841

3942
override fun setTheme(themeId: Long) {}

0 commit comments

Comments
 (0)