Bug fixes
This commit is contained in:
parent
b8542ba688
commit
b978683b7e
11 changed files with 67 additions and 332 deletions
|
@ -116,21 +116,6 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="dev.lucasnlm.antimine.TvGameActivity"
|
||||
android:configChanges="screenSize|orientation"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.MAIN"/>-->
|
||||
<!-- <category android:name="android.intent.category.LAUNCHER"/>-->
|
||||
<!-- </intent-filter>-->
|
||||
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.MAIN" />-->
|
||||
<!-- <category android:name="android.intent.category.LEANBACK_LAUNCHER" />-->
|
||||
<!-- </intent-filter>-->
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="dev.lucasnlm.antimine.text.TextActivity"
|
||||
android:theme="@style/AppTheme">
|
||||
|
|
|
@ -527,6 +527,7 @@ class GameActivity : ThematicActivity(R.layout.activity_game), DialogInterface.O
|
|||
keepScreenOn(true)
|
||||
}
|
||||
Event.Victory -> {
|
||||
val isResuming = (status == Status.PreGame)
|
||||
val score = Score(
|
||||
rightMines,
|
||||
totalMines,
|
||||
|
@ -538,10 +539,13 @@ class GameActivity : ThematicActivity(R.layout.activity_game), DialogInterface.O
|
|||
gameViewModel.victory()
|
||||
refreshNewGameButton()
|
||||
keepScreenOn(false)
|
||||
waitAndShowEndGameDialog(
|
||||
victory = true,
|
||||
await = false
|
||||
)
|
||||
|
||||
if (!isResuming) {
|
||||
waitAndShowEndGameDialog(
|
||||
victory = true,
|
||||
await = false
|
||||
)
|
||||
}
|
||||
}
|
||||
Event.GameOver -> {
|
||||
val isResuming = (status == Status.PreGame)
|
||||
|
@ -555,12 +559,14 @@ class GameActivity : ThematicActivity(R.layout.activity_game), DialogInterface.O
|
|||
keepScreenOn(false)
|
||||
gameViewModel.stopClock()
|
||||
|
||||
GlobalScope.launch(context = Dispatchers.Main) {
|
||||
gameViewModel.gameOver(isResuming)
|
||||
waitAndShowEndGameDialog(
|
||||
victory = false,
|
||||
await = true
|
||||
)
|
||||
if (!isResuming) {
|
||||
GlobalScope.launch(context = Dispatchers.Main) {
|
||||
gameViewModel.gameOver(isResuming)
|
||||
waitAndShowEndGameDialog(
|
||||
victory = false,
|
||||
await = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> { }
|
||||
|
|
|
@ -1,279 +0,0 @@
|
|||
package dev.lucasnlm.antimine
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.text.format.DateUtils
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.os.HandlerCompat
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.lucasnlm.antimine.about.AboutActivity
|
||||
import dev.lucasnlm.antimine.common.level.models.Difficulty
|
||||
import dev.lucasnlm.antimine.common.level.models.Event
|
||||
import dev.lucasnlm.antimine.common.level.models.Score
|
||||
import dev.lucasnlm.antimine.common.level.models.Status
|
||||
import dev.lucasnlm.antimine.common.level.viewmodel.GameViewModel
|
||||
import dev.lucasnlm.antimine.custom.CustomLevelDialogFragment
|
||||
import dev.lucasnlm.antimine.level.view.LevelFragment
|
||||
import dev.lucasnlm.antimine.preferences.PreferencesActivity
|
||||
import kotlinx.android.synthetic.main.activity_tv_game.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class TvGameActivity : AppCompatActivity() {
|
||||
private val gameViewModel by viewModel<GameViewModel>()
|
||||
|
||||
private var status: Status = Status.PreGame
|
||||
private var totalMines: Int = 0
|
||||
private var totalArea: Int = 0
|
||||
private var rightMines: Int = 0
|
||||
private var currentTime: Long = 0
|
||||
|
||||
private var keepConfirmingNewGame = true
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_tv_game)
|
||||
bindViewModel()
|
||||
|
||||
PreferenceManager.setDefaultValues(this, R.xml.preferences, false)
|
||||
|
||||
loadGameFragment()
|
||||
}
|
||||
|
||||
private fun bindViewModel() = gameViewModel.apply {
|
||||
eventObserver.observe(
|
||||
this@TvGameActivity,
|
||||
{
|
||||
onGameEvent(it)
|
||||
}
|
||||
)
|
||||
|
||||
elapsedTimeSeconds.observe(
|
||||
this@TvGameActivity,
|
||||
{
|
||||
timer.apply {
|
||||
visibility = if (it == 0L) View.GONE else View.VISIBLE
|
||||
text = DateUtils.formatElapsedTime(it)
|
||||
}
|
||||
currentTime = it
|
||||
}
|
||||
)
|
||||
|
||||
mineCount.observe(
|
||||
this@TvGameActivity,
|
||||
{
|
||||
minesCount.apply {
|
||||
visibility = View.VISIBLE
|
||||
text = it.toString()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
difficulty.observe(
|
||||
this@TvGameActivity,
|
||||
{
|
||||
// onChangeDifficulty(it)
|
||||
}
|
||||
)
|
||||
|
||||
field.observe(
|
||||
this@TvGameActivity,
|
||||
{ area ->
|
||||
val mines = area.filter { it.hasMine }
|
||||
totalArea = area.count()
|
||||
totalMines = mines.count()
|
||||
rightMines = mines.map { if (it.mark.isFlag()) 1 else 0 }.sum()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (status == Status.Running) {
|
||||
gameViewModel.resumeGame()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
|
||||
if (status == Status.Running) {
|
||||
gameViewModel.pauseGame()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadGameFragment() {
|
||||
val fragmentManager = supportFragmentManager
|
||||
|
||||
fragmentManager.popBackStack()
|
||||
|
||||
fragmentManager.findFragmentById(R.id.levelContainer)?.let { it ->
|
||||
fragmentManager.beginTransaction().apply {
|
||||
remove(it)
|
||||
commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
fragmentManager.beginTransaction().apply {
|
||||
replace(R.id.levelContainer, LevelFragment())
|
||||
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
|
||||
commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun newGameConfirmation(action: () -> Unit) {
|
||||
AlertDialog.Builder(this).apply {
|
||||
setTitle(R.string.new_game)
|
||||
setMessage(R.string.retry_sure)
|
||||
setPositiveButton(R.string.resume) { _, _ -> action() }
|
||||
setNegativeButton(R.string.cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showCustomLevelDialog() {
|
||||
CustomLevelDialogFragment().apply {
|
||||
show(supportFragmentManager, "custom_level_fragment")
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAbout() {
|
||||
Intent(this, AboutActivity::class.java).apply {
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSettings() {
|
||||
Intent(this, PreferencesActivity::class.java).apply {
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showVictory() {
|
||||
AlertDialog.Builder(this).apply {
|
||||
setTitle(R.string.you_won)
|
||||
setMessage(R.string.all_mines_disabled)
|
||||
setCancelable(false)
|
||||
setPositiveButton(R.string.new_game) { _, _ ->
|
||||
GlobalScope.launch {
|
||||
gameViewModel.startNewGame()
|
||||
}
|
||||
}
|
||||
setNegativeButton(R.string.cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun waitAndShowConfirmNewGame() {
|
||||
if (keepConfirmingNewGame) {
|
||||
HandlerCompat.postDelayed(
|
||||
Handler(),
|
||||
{
|
||||
if (status is Status.Over && !isFinishing) {
|
||||
AlertDialog.Builder(this).apply {
|
||||
setTitle(R.string.new_game)
|
||||
setMessage(R.string.new_game_request)
|
||||
setPositiveButton(R.string.yes) { _, _ ->
|
||||
GlobalScope.launch {
|
||||
gameViewModel.startNewGame()
|
||||
}
|
||||
}
|
||||
setNegativeButton(R.string.cancel, null)
|
||||
}.show()
|
||||
|
||||
keepConfirmingNewGame = false
|
||||
}
|
||||
},
|
||||
null,
|
||||
DateUtils.SECOND_IN_MILLIS
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun waitAndShowGameOverConfirmNewGame() {
|
||||
HandlerCompat.postDelayed(
|
||||
Handler(),
|
||||
{
|
||||
if (status is Status.Over && !isFinishing) {
|
||||
AlertDialog.Builder(this).apply {
|
||||
setTitle(R.string.you_lost)
|
||||
setMessage(R.string.new_game_request)
|
||||
setPositiveButton(R.string.yes) { _, _ ->
|
||||
GlobalScope.launch {
|
||||
gameViewModel.startNewGame()
|
||||
}
|
||||
}
|
||||
setNegativeButton(R.string.cancel, null)
|
||||
}.show()
|
||||
}
|
||||
},
|
||||
null,
|
||||
DateUtils.SECOND_IN_MILLIS
|
||||
)
|
||||
}
|
||||
|
||||
private fun changeDifficulty(newDifficulty: Difficulty) {
|
||||
if (status == Status.PreGame) {
|
||||
GlobalScope.launch {
|
||||
gameViewModel.startNewGame(newDifficulty)
|
||||
}
|
||||
} else {
|
||||
newGameConfirmation {
|
||||
GlobalScope.launch {
|
||||
gameViewModel.startNewGame(newDifficulty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onGameEvent(event: Event) {
|
||||
when (event) {
|
||||
Event.ResumeGame -> {
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
Event.StartNewGame -> {
|
||||
status = Status.PreGame
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
Event.Resume, Event.Running -> {
|
||||
status = Status.Running
|
||||
gameViewModel.runClock()
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
Event.Victory -> {
|
||||
val score = Score(
|
||||
rightMines,
|
||||
totalMines,
|
||||
totalArea
|
||||
)
|
||||
status = Status.Over(currentTime, score)
|
||||
gameViewModel.stopClock()
|
||||
gameViewModel.revealAllEmptyAreas()
|
||||
invalidateOptionsMenu()
|
||||
showVictory()
|
||||
}
|
||||
Event.GameOver -> {
|
||||
val score = Score(
|
||||
rightMines,
|
||||
totalMines,
|
||||
totalArea
|
||||
)
|
||||
status = Status.Over(currentTime, score)
|
||||
invalidateOptionsMenu()
|
||||
gameViewModel.stopClock()
|
||||
|
||||
GlobalScope.launch(context = Dispatchers.Main) {
|
||||
gameViewModel.gameOver(false)
|
||||
waitAndShowGameOverConfirmNewGame()
|
||||
}
|
||||
}
|
||||
else -> { }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,8 +12,11 @@ import androidx.fragment.app.FragmentManager
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import dev.lucasnlm.antimine.R
|
||||
import dev.lucasnlm.antimine.common.level.viewmodel.GameViewModel
|
||||
import dev.lucasnlm.antimine.core.preferences.IPreferencesRepository
|
||||
import dev.lucasnlm.antimine.level.viewmodel.EndGameDialogEvent
|
||||
import dev.lucasnlm.antimine.level.viewmodel.EndGameDialogViewModel
|
||||
import dev.lucasnlm.external.Ads
|
||||
import dev.lucasnlm.external.IAdsManager
|
||||
import dev.lucasnlm.external.IInstantAppManager
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import org.koin.android.ext.android.inject
|
||||
|
@ -22,6 +25,8 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
|
|||
|
||||
class EndGameDialogFragment : AppCompatDialogFragment() {
|
||||
private val instantAppManager: IInstantAppManager by inject()
|
||||
private val adsManager: IAdsManager by inject()
|
||||
private val preferencesRepository: IPreferencesRepository by inject()
|
||||
|
||||
private val endGameViewModel by viewModel<EndGameDialogViewModel>()
|
||||
private val gameViewModel by sharedViewModel<GameViewModel>()
|
||||
|
@ -76,6 +81,12 @@ class EndGameDialogFragment : AppCompatDialogFragment() {
|
|||
} else {
|
||||
setNeutralButton(R.string.retry) { _, _ ->
|
||||
gameViewModel.retryObserver.postValue(Unit)
|
||||
|
||||
activity?.let {
|
||||
if (!preferencesRepository.isPremiumEnabled()) {
|
||||
adsManager.requestRewarded(it, Ads.RewardsAds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
package dev.lucasnlm.antimine.splash
|
||||
|
||||
import android.app.UiModeManager
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import dev.lucasnlm.antimine.GameActivity
|
||||
import dev.lucasnlm.antimine.TvGameActivity
|
||||
import dev.lucasnlm.antimine.support.IapHandler
|
||||
import dev.lucasnlm.external.IBillingManager
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class SplashActivity : AppCompatActivity() {
|
||||
private val billingManager: IBillingManager by inject()
|
||||
private val iapHandler: IapHandler by inject()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val uiModeManager: UiModeManager = getSystemService(UI_MODE_SERVICE) as UiModeManager
|
||||
if (uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) {
|
||||
Intent(this, TvGameActivity::class.java).run { startActivity(this) }
|
||||
} else {
|
||||
Intent(this, GameActivity::class.java).run { startActivity(this) }
|
||||
}
|
||||
billingManager.start(iapHandler)
|
||||
|
||||
Intent(this, GameActivity::class.java).run { startActivity(this) }
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import dev.lucasnlm.antimine.R
|
|||
import dev.lucasnlm.antimine.core.analytics.IAnalyticsManager
|
||||
import dev.lucasnlm.antimine.core.analytics.models.Analytics
|
||||
import dev.lucasnlm.antimine.core.themes.repository.IThemeRepository
|
||||
import dev.lucasnlm.external.Ads
|
||||
import dev.lucasnlm.external.IAdsManager
|
||||
import dev.lucasnlm.external.IBillingManager
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -43,7 +44,7 @@ class SupportAppDialogFragment : AppCompatDialogFragment() {
|
|||
if (showUnlockMessage) {
|
||||
setNeutralButton(R.string.try_it) { _, _ ->
|
||||
analyticsManager.sentEvent(Analytics.UnlockRewardedDialog)
|
||||
adsManager.requestRewarded(requireActivity(), "ca-app-pub-3940256099942544/5224354917") {
|
||||
adsManager.requestRewarded(requireActivity(), Ads.RewardsAds) {
|
||||
if (targetThemeId > 0) {
|
||||
themeRepository.setTheme(targetThemeId)
|
||||
requireActivity().recreate()
|
||||
|
|
|
@ -141,7 +141,7 @@ class GameViewModel(
|
|||
levelSetup.postValue(setup)
|
||||
refreshField()
|
||||
|
||||
eventObserver.postValue(Event.StartNewGame)
|
||||
eventObserver.postValue(Event.ResumeGame)
|
||||
|
||||
analyticsManager.sentEvent(
|
||||
Analytics.RetryGame(
|
||||
|
|
|
@ -6,5 +6,9 @@ import android.content.Context
|
|||
interface IAdsManager {
|
||||
fun start(context: Context)
|
||||
fun isReady(): Boolean
|
||||
fun requestRewarded(activity: Activity, adUnitId: String, onRewarded: () -> Unit)
|
||||
fun requestRewarded(activity: Activity, adUnitId: String, onRewarded: (() -> Unit)? = null)
|
||||
}
|
||||
|
||||
object Ads {
|
||||
const val RewardsAds = "ca-app-pub-3940256099942544/5224354917"
|
||||
}
|
||||
|
|
|
@ -8,5 +8,5 @@ class AdsManager : IAdsManager {
|
|||
|
||||
override fun isReady(): Boolean = false
|
||||
|
||||
override fun requestRewarded(activity: Activity, adUnitId: String, onRewarded: () -> Unit) { }
|
||||
override fun requestRewarded(activity: Activity, adUnitId: String, onRewarded: (() -> Unit)?) { }
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback
|
|||
|
||||
class AdsManager : IAdsManager {
|
||||
private var unlockTheme: RewardedAd? = null
|
||||
private val rewardedAdId = Ads.RewardsAds
|
||||
|
||||
override fun start(context: Context) {
|
||||
MobileAds.initialize(context) {
|
||||
|
@ -22,7 +23,7 @@ class AdsManager : IAdsManager {
|
|||
}
|
||||
|
||||
private fun loadRewardedAd(context: Context): RewardedAd {
|
||||
return RewardedAd(context, "ca-app-pub-3940256099942544/5224354917").apply {
|
||||
return RewardedAd(context, rewardedAdId).apply {
|
||||
val adLoadCallback = object : RewardedAdLoadCallback() {
|
||||
override fun onRewardedAdLoaded() {
|
||||
// Loaded
|
||||
|
@ -41,7 +42,7 @@ class AdsManager : IAdsManager {
|
|||
return unlockTheme != null
|
||||
}
|
||||
|
||||
override fun requestRewarded(activity: Activity, adUnitId: String, onRewarded: () -> Unit) {
|
||||
override fun requestRewarded(activity: Activity, adUnitId: String, onRewarded: (() -> Unit)?) {
|
||||
if (isReady()) {
|
||||
val context = activity.applicationContext
|
||||
|
||||
|
@ -56,7 +57,7 @@ class AdsManager : IAdsManager {
|
|||
}
|
||||
|
||||
override fun onUserEarnedReward(@NonNull reward: RewardItem) {
|
||||
onRewarded()
|
||||
onRewarded?.invoke()
|
||||
}
|
||||
|
||||
override fun onRewardedAdFailedToShow(adError: AdError) {
|
||||
|
|
|
@ -24,13 +24,16 @@ class BillingManager(
|
|||
}
|
||||
|
||||
private fun handlePurchases(purchases: List<Purchase>) {
|
||||
purchases.firstOrNull {
|
||||
val status: Boolean = purchases.firstOrNull {
|
||||
it.sku == BASIC_SUPPORT
|
||||
}?.let {
|
||||
if (it.purchaseState == Purchase.PurchaseState.PURCHASED) {
|
||||
unlockAppListener?.onLockStatusChanged(isFreeUnlock = false, status = true)
|
||||
}.let {
|
||||
when (it?.purchaseState) {
|
||||
Purchase.PurchaseState.PURCHASED, Purchase.PurchaseState.PENDING -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
unlockAppListener?.onLockStatusChanged(isFreeUnlock = false, status = status)
|
||||
}
|
||||
|
||||
override fun onBillingServiceDisconnected() {
|
||||
|
@ -39,24 +42,28 @@ class BillingManager(
|
|||
}
|
||||
|
||||
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
val purchasesList: List<Purchase> = if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
// The BillingClient is ready. You can query purchases here.
|
||||
|
||||
billingClient.queryPurchases(BillingClient.SkuType.INAPP).purchasesList?.let {
|
||||
handlePurchases(it.toList())
|
||||
billingClient.queryPurchases(BillingClient.SkuType.INAPP).purchasesList.let {
|
||||
it?.toList() ?: listOf()
|
||||
}
|
||||
} else {
|
||||
listOf()
|
||||
}
|
||||
|
||||
handlePurchases(purchasesList)
|
||||
}
|
||||
|
||||
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
val purchasesList: List<Purchase> = if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
// The BillingClient is ready. You can query purchases here.
|
||||
purchases?.let {
|
||||
handlePurchases(it.toList())
|
||||
}
|
||||
purchases?.toList() ?: listOf()
|
||||
} else {
|
||||
unlockAppListener?.onLockStatusChanged(status = false)
|
||||
listOf()
|
||||
}
|
||||
|
||||
handlePurchases(purchasesList)
|
||||
}
|
||||
|
||||
override fun start(unlockAppListener: UnlockAppListener) {
|
||||
|
|
Loading…
Reference in a new issue