diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e58b9851..e4ac08d6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -116,21 +116,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt b/app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt
index 3e41e680..0b926159 100644
--- a/app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt
+++ b/app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt
@@ -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 -> { }
diff --git a/app/src/main/java/dev/lucasnlm/antimine/TvGameActivity.kt b/app/src/main/java/dev/lucasnlm/antimine/TvGameActivity.kt
deleted file mode 100644
index 9a11a4e4..00000000
--- a/app/src/main/java/dev/lucasnlm/antimine/TvGameActivity.kt
+++ /dev/null
@@ -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()
-
- 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 -> { }
- }
- }
-}
diff --git a/app/src/main/java/dev/lucasnlm/antimine/level/view/EndGameDialogFragment.kt b/app/src/main/java/dev/lucasnlm/antimine/level/view/EndGameDialogFragment.kt
index 45ed5f53..dbe95e58 100644
--- a/app/src/main/java/dev/lucasnlm/antimine/level/view/EndGameDialogFragment.kt
+++ b/app/src/main/java/dev/lucasnlm/antimine/level/view/EndGameDialogFragment.kt
@@ -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()
private val gameViewModel by sharedViewModel()
@@ -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)
+ }
+ }
}
}
}
diff --git a/app/src/main/java/dev/lucasnlm/antimine/splash/SplashActivity.kt b/app/src/main/java/dev/lucasnlm/antimine/splash/SplashActivity.kt
index bd56b95c..02d80c8e 100644
--- a/app/src/main/java/dev/lucasnlm/antimine/splash/SplashActivity.kt
+++ b/app/src/main/java/dev/lucasnlm/antimine/splash/SplashActivity.kt
@@ -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()
}
}
diff --git a/app/src/main/java/dev/lucasnlm/antimine/support/SupportAppDialogFragment.kt b/app/src/main/java/dev/lucasnlm/antimine/support/SupportAppDialogFragment.kt
index 165f3de3..b8c0d60d 100644
--- a/app/src/main/java/dev/lucasnlm/antimine/support/SupportAppDialogFragment.kt
+++ b/app/src/main/java/dev/lucasnlm/antimine/support/SupportAppDialogFragment.kt
@@ -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()
diff --git a/common/src/main/java/dev/lucasnlm/antimine/common/level/viewmodel/GameViewModel.kt b/common/src/main/java/dev/lucasnlm/antimine/common/level/viewmodel/GameViewModel.kt
index bd401d81..350b0d66 100644
--- a/common/src/main/java/dev/lucasnlm/antimine/common/level/viewmodel/GameViewModel.kt
+++ b/common/src/main/java/dev/lucasnlm/antimine/common/level/viewmodel/GameViewModel.kt
@@ -141,7 +141,7 @@ class GameViewModel(
levelSetup.postValue(setup)
refreshField()
- eventObserver.postValue(Event.StartNewGame)
+ eventObserver.postValue(Event.ResumeGame)
analyticsManager.sentEvent(
Analytics.RetryGame(
diff --git a/external/src/main/java/dev/lucasnlm/external/IAdsManager.kt b/external/src/main/java/dev/lucasnlm/external/IAdsManager.kt
index 9e7201f1..ec6f5695 100644
--- a/external/src/main/java/dev/lucasnlm/external/IAdsManager.kt
+++ b/external/src/main/java/dev/lucasnlm/external/IAdsManager.kt
@@ -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"
}
diff --git a/foss/src/main/java/dev/lucasnlm/external/AdsManager.kt b/foss/src/main/java/dev/lucasnlm/external/AdsManager.kt
index e77b8301..4989bcb1 100644
--- a/foss/src/main/java/dev/lucasnlm/external/AdsManager.kt
+++ b/foss/src/main/java/dev/lucasnlm/external/AdsManager.kt
@@ -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)?) { }
}
diff --git a/proprietary/src/main/java/dev/lucasnlm/external/AdsManager.kt b/proprietary/src/main/java/dev/lucasnlm/external/AdsManager.kt
index f4a523a5..16c55ba4 100644
--- a/proprietary/src/main/java/dev/lucasnlm/external/AdsManager.kt
+++ b/proprietary/src/main/java/dev/lucasnlm/external/AdsManager.kt
@@ -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) {
diff --git a/proprietary/src/main/java/dev/lucasnlm/external/BillingManager.kt b/proprietary/src/main/java/dev/lucasnlm/external/BillingManager.kt
index 2ca884a0..099d8630 100644
--- a/proprietary/src/main/java/dev/lucasnlm/external/BillingManager.kt
+++ b/proprietary/src/main/java/dev/lucasnlm/external/BillingManager.kt
@@ -24,13 +24,16 @@ class BillingManager(
}
private fun handlePurchases(purchases: List) {
- 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 = 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?) {
- if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
+ val purchasesList: List = 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) {