diff --git a/app/build.gradle b/app/build.gradle index 73ebd219..c73b300d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { defaultConfig { // versionCode and versionName must be hardcoded to support F-droid - versionCode 805021 - versionName '8.5.2' + versionCode 805041 + versionName '8.5.4' minSdkVersion 21 targetSdkVersion 30 multiDexEnabled true diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 604e298a..ab649eea 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -47,41 +47,11 @@ - - - + - - - - - - - - - - - - - - - - - diff --git a/app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt b/app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt index ce8840c3..5d66796c 100644 --- a/app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt +++ b/app/src/main/java/dev/lucasnlm/antimine/GameActivity.kt @@ -659,7 +659,7 @@ class GameActivity : ThematicActivity(R.layout.activity_game), DialogInterface.O score?.rightMines ?: 0, score?.totalMines ?: 0, currentGameStatus.time, - if (gameResult == GameResult.Victory) 1 else 0 + if (gameResult == GameResult.Victory) 2 else 1 ).apply { showAllowingStateLoss(supportFragmentManager, EndGameDialogFragment.TAG) } @@ -930,15 +930,19 @@ class GameActivity : ThematicActivity(R.layout.activity_game), DialogInterface.O } private fun refreshAds() { - val isTutorialComplete = preferencesRepository.isTutorialCompleted() - if (isTutorialComplete && !preferencesRepository.isPremiumEnabled() && billingManager.isEnabled()) { - if (!instantAppManager.isEnabled(this)) { - navigationView.menu.setGroupVisible(R.id.remove_ads_group, true) - ad_placeholder.visibility = View.VISIBLE - ad_placeholder.loadAd() + if (featureFlagManager.isInAppAdsEnabled()) { + val isTutorialComplete = preferencesRepository.isTutorialCompleted() + if (isTutorialComplete && !preferencesRepository.isPremiumEnabled() && billingManager.isEnabled()) { + if (!instantAppManager.isEnabled(this)) { + navigationView.menu.setGroupVisible(R.id.remove_ads_group, true) + ad_placeholder.visibility = View.VISIBLE + ad_placeholder.loadAd() + } + } else { + navigationView.menu.setGroupVisible(R.id.remove_ads_group, false) + ad_placeholder.visibility = View.GONE } } else { - navigationView.menu.setGroupVisible(R.id.remove_ads_group, false) ad_placeholder.visibility = View.GONE } } diff --git a/app/src/main/java/dev/lucasnlm/antimine/gameover/EndGameDialogFragment.kt b/app/src/main/java/dev/lucasnlm/antimine/gameover/EndGameDialogFragment.kt index cc026549..7fb9fb7d 100644 --- a/app/src/main/java/dev/lucasnlm/antimine/gameover/EndGameDialogFragment.kt +++ b/app/src/main/java/dev/lucasnlm/antimine/gameover/EndGameDialogFragment.kt @@ -3,13 +3,16 @@ package dev.lucasnlm.antimine.gameover import android.annotation.SuppressLint import android.app.Dialog import android.content.DialogInterface +import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.widget.ImageView import android.widget.TextView +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialogFragment +import androidx.appcompat.widget.AppCompatButton import androidx.fragment.app.FragmentManager import androidx.lifecycle.lifecycleScope import androidx.lifecycle.viewModelScope @@ -19,24 +22,37 @@ import dev.lucasnlm.antimine.core.preferences.IPreferencesRepository import dev.lucasnlm.antimine.gameover.model.GameResult import dev.lucasnlm.antimine.gameover.viewmodel.EndGameDialogEvent import dev.lucasnlm.antimine.gameover.viewmodel.EndGameDialogViewModel +import dev.lucasnlm.antimine.preferences.PreferencesActivity +import dev.lucasnlm.external.Ads +import dev.lucasnlm.external.IAdsManager +import dev.lucasnlm.external.IBillingManager import dev.lucasnlm.external.IInstantAppManager +import dev.lucasnlm.external.view.AdPlaceHolderView +import kotlinx.android.synthetic.main.view_play_games_button.view.* import kotlinx.android.synthetic.main.view_stats.* import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.singleOrNull import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.viewModel class EndGameDialogFragment : AppCompatDialogFragment() { + private val adsManager: IAdsManager by inject() private val instantAppManager: IInstantAppManager by inject() private val endGameViewModel by viewModel() private val gameViewModel by sharedViewModel() private val preferencesRepository: IPreferencesRepository by inject() + private val billingManager: IBillingManager by inject() private var revealMinesOnDismiss = true override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + if (!preferencesRepository.isPremiumEnabled()) { + billingManager.start() + } + arguments?.run { endGameViewModel.sendEvent( EndGameDialogEvent.BuildCustomEndGame( @@ -61,8 +77,12 @@ class EndGameDialogFragment : AppCompatDialogFragment() { override fun onDismiss(dialog: DialogInterface) { if (revealMinesOnDismiss) { - gameViewModel.viewModelScope.launch { - gameViewModel.revealMines() + activity?.let { + if (!it.isFinishing) { + gameViewModel.viewModelScope.launch { + gameViewModel.revealMines() + } + } } } super.onDismiss(dialog) @@ -88,7 +108,85 @@ class EndGameDialogFragment : AppCompatDialogFragment() { } } - findViewById(R.id.received_message).apply { + val adsView: AdPlaceHolderView = findViewById(R.id.ads) + val shareButton: AppCompatButton = findViewById(R.id.share) + val newGameButton: AppCompatButton = findViewById(R.id.new_game) + val continueButton: AppCompatButton = findViewById(R.id.continue_game) + val removeAdsButton: AppCompatButton = findViewById(R.id.remove_ads) + val settingsButton: View = findViewById(R.id.settings) + val closeButton: View = findViewById(R.id.close) + val receivedMessage: TextView = findViewById(R.id.received_message) + + shareButton.setOnClickListener { + revealMinesOnDismiss = false + gameViewModel.shareObserver.postValue(Unit) + } + + newGameButton.setOnClickListener { + revealMinesOnDismiss = false + gameViewModel.startNewGame() + dismissAllowingStateLoss() + } + + continueButton.setOnClickListener { + revealMinesOnDismiss = false + + if (preferencesRepository.isPremiumEnabled()) { + gameViewModel.continueObserver.postValue(Unit) + dismissAllowingStateLoss() + } else { + showAdsAndContinue() + } + } + + settingsButton.setOnClickListener { + showSettings() + } + + closeButton.setOnClickListener { + dismissAllowingStateLoss() + } + + if (state.gameResult == GameResult.Victory) { + if (!instantAppManager.isEnabled(context)) { + shareButton.visibility = View.GONE + } + shareButton.visibility = View.VISIBLE + continueButton.visibility = View.GONE + } else { + shareButton.visibility = View.GONE + + if (state.showContinueButton) { + continueButton.visibility = View.VISIBLE + if (!preferencesRepository.isPremiumEnabled()) { + continueButton.compoundDrawablePadding = 0 + continueButton.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.watch_ads_icon, 0, 0, 0 + ) + } + } else { + continueButton.visibility = View.GONE + } + } + + if (!preferencesRepository.isPremiumEnabled() && !instantAppManager.isEnabled(context)) { + activity?.let { activity -> + adsView.visibility = View.VISIBLE + removeAdsButton.visibility = View.VISIBLE + val label = context.getString(R.string.remove_ad) + val price = billingManager.getPrice().singleOrNull() + val unlockLabel = price?.let { "$label - $it" } ?: label + removeAdsButton.text = unlockLabel + removeAdsButton.setOnClickListener { + lifecycleScope.launch { + billingManager.charge(activity) + adsView.visibility = View.GONE + } + } + } + } + + receivedMessage.apply { if (state.received > 0 && state.gameResult == GameResult.Victory && preferencesRepository.useHelp() @@ -99,47 +197,39 @@ class EndGameDialogFragment : AppCompatDialogFragment() { visibility = View.GONE } } - - findViewById(R.id.close).setOnClickListener { - dismissAllowingStateLoss() - } - - if (state.gameResult == GameResult.Victory) { - revealMinesOnDismiss = false - if (!instantAppManager.isEnabled(context)) { - setNeutralButton(R.string.share) { _, _ -> - gameViewModel.shareObserver.postValue(Unit) - } - } - } else { - if (state.showContinueButton) { - setNegativeButton(R.string.retry) { _, _ -> - revealMinesOnDismiss = false - gameViewModel.retryObserver.postValue(Unit) - } - - setNeutralButton(R.string.continue_game) { _, _ -> - revealMinesOnDismiss = false - gameViewModel.continueObserver.postValue(Unit) - } - } else { - setNeutralButton(R.string.retry) { _, _ -> - revealMinesOnDismiss = false - gameViewModel.retryObserver.postValue(Unit) - } - } - } } } } setView(view) - - setPositiveButton(R.string.new_game) { _, _ -> - gameViewModel.startNewGame() - } }.create() + private fun showSettings() { + startActivity(Intent(requireContext(), PreferencesActivity::class.java)) + } + + private fun showAdsAndContinue() { + activity?.let { + if (!it.isFinishing) { + adsManager.requestRewarded( + it, + Ads.RewardsAds, + onRewarded = { + gameViewModel.continueObserver.postValue(Unit) + dismissAllowingStateLoss() + }, + onFail = { + Toast.makeText( + it.applicationContext, + R.string.unknown_error, + Toast.LENGTH_SHORT + ).show() + } + ) + } + } + } + companion object { fun newInstance( gameResult: GameResult, diff --git a/app/src/main/res/drawable/retry.xml b/app/src/main/res/drawable/retry.xml index c9701566..bbec7a73 100644 --- a/app/src/main/res/drawable/retry.xml +++ b/app/src/main/res/drawable/retry.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" - android:viewportHeight="24"> + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> diff --git a/app/src/main/res/drawable/translate.xml b/app/src/main/res/drawable/translate.xml index 475bb6e2..3b75529f 100644 --- a/app/src/main/res/drawable/translate.xml +++ b/app/src/main/res/drawable/translate.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/tutorial.xml b/app/src/main/res/drawable/tutorial.xml index 20d5e297..9b09c549 100644 --- a/app/src/main/res/drawable/tutorial.xml +++ b/app/src/main/res/drawable/tutorial.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/watch_ads_icon.xml b/app/src/main/res/drawable/watch_ads_icon.xml new file mode 100644 index 00000000..d4d954df --- /dev/null +++ b/app/src/main/res/drawable/watch_ads_icon.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/dialog_end_game.xml b/app/src/main/res/layout/dialog_end_game.xml index cafda748..59d89bf9 100644 --- a/app/src/main/res/layout/dialog_end_game.xml +++ b/app/src/main/res/layout/dialog_end_game.xml @@ -31,6 +31,7 @@ android:textAlignment="center" android:gravity="center_horizontal" android:textAllCaps="true" + android:textColor="@color/accent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/title_emoji" @@ -54,14 +55,16 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/you_have_received" - android:layout_marginTop="4dp" + android:layout_marginVertical="4dp" android:textAlignment="center" android:gravity="center" + android:visibility="gone" app:drawableEndCompat="@drawable/tip" app:drawableTint="@color/accent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/subtitle"/> + app:layout_constraintTop_toBottomOf="@+id/subtitle" + tools:visibility="visible"/> + + + + + + + + + + + + + + + + + diff --git a/common/build.gradle b/common/build.gradle index c87ab7c5..197afc9f 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { // versionCode and versionName must be hardcoded to support F-droid - versionCode 805021 - versionName '8.5.2' + versionCode 805041 + versionName '8.5.4' minSdkVersion 21 targetSdkVersion 30 testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' diff --git a/common/src/main/res/values-en-rUS/strings.xml b/common/src/main/res/values-en-rUS/strings.xml index 8b1c5ec5..9916cfb6 100644 --- a/common/src/main/res/values-en-rUS/strings.xml +++ b/common/src/main/res/values-en-rUS/strings.xml @@ -79,7 +79,7 @@ Open Flag Retry - Continue + Continue this game Empty Impossible to do that now You have received: %1$d diff --git a/external/src/main/java/dev/lucasnlm/external/IFeatureFlagManager.kt b/external/src/main/java/dev/lucasnlm/external/IFeatureFlagManager.kt index 2b843615..5ed9f4e9 100644 --- a/external/src/main/java/dev/lucasnlm/external/IFeatureFlagManager.kt +++ b/external/src/main/java/dev/lucasnlm/external/IFeatureFlagManager.kt @@ -3,4 +3,5 @@ package dev.lucasnlm.external interface IFeatureFlagManager { fun isGameHistoryEnabled(): Boolean fun isRateUsEnabled(): Boolean + fun isInAppAdsEnabled(): Boolean } diff --git a/foss/build.gradle b/foss/build.gradle index b95a0976..fb66e643 100644 --- a/foss/build.gradle +++ b/foss/build.gradle @@ -8,8 +8,8 @@ android { compileSdkVersion 30 defaultConfig { - versionCode 805021 - versionName '8.5.2' + versionCode 805041 + versionName '8.5.4' minSdkVersion 21 targetSdkVersion 30 } diff --git a/foss/src/main/java/dev/lucasnlm/external/FeatureFlagManager.kt b/foss/src/main/java/dev/lucasnlm/external/FeatureFlagManager.kt index 40b6cf35..80dcbfc4 100644 --- a/foss/src/main/java/dev/lucasnlm/external/FeatureFlagManager.kt +++ b/foss/src/main/java/dev/lucasnlm/external/FeatureFlagManager.kt @@ -3,4 +3,5 @@ package dev.lucasnlm.external class FeatureFlagManager : IFeatureFlagManager { override fun isGameHistoryEnabled(): Boolean = true override fun isRateUsEnabled(): Boolean = false + override fun isInAppAdsEnabled(): Boolean = false } diff --git a/proprietary/build.gradle b/proprietary/build.gradle index 4402371b..0178e7a9 100644 --- a/proprietary/build.gradle +++ b/proprietary/build.gradle @@ -12,8 +12,8 @@ android { compileSdkVersion 30 defaultConfig { - versionCode 805021 - versionName '8.5.2' + versionCode 805041 + versionName '8.5.4' minSdkVersion 21 targetSdkVersion 30 } diff --git a/proprietary/src/main/java/dev/lucasnlm/external/FeatureFlagManager.kt b/proprietary/src/main/java/dev/lucasnlm/external/FeatureFlagManager.kt index 7c3f285c..1d092ec4 100644 --- a/proprietary/src/main/java/dev/lucasnlm/external/FeatureFlagManager.kt +++ b/proprietary/src/main/java/dev/lucasnlm/external/FeatureFlagManager.kt @@ -3,4 +3,5 @@ package dev.lucasnlm.external class FeatureFlagManager : IFeatureFlagManager { override fun isGameHistoryEnabled(): Boolean = false override fun isRateUsEnabled(): Boolean = true + override fun isInAppAdsEnabled(): Boolean = false } diff --git a/proprietary/src/main/java/dev/lucasnlm/external/view/AdPlaceHolderView.kt b/proprietary/src/main/java/dev/lucasnlm/external/view/AdPlaceHolderView.kt index 9e27b155..db8d6273 100644 --- a/proprietary/src/main/java/dev/lucasnlm/external/view/AdPlaceHolderView.kt +++ b/proprietary/src/main/java/dev/lucasnlm/external/view/AdPlaceHolderView.kt @@ -2,7 +2,6 @@ package dev.lucasnlm.external.view import android.content.Context import android.util.AttributeSet -import android.view.View import android.widget.FrameLayout import com.google.android.gms.ads.AdRequest import com.google.android.gms.ads.AdSize @@ -21,17 +20,19 @@ class AdPlaceHolderView : FrameLayout { init { addView(adView) - setOnClickListener { - adView.performClick() - this.visibility = View.GONE - } +// setOnClickListener { +// adView.performClick() +// this.visibility = View.GONE +// } + + loadAd() } fun loadAd() { adView.loadAd(AdRequest.Builder().build()) - if (!adView.isLoading) { - this.visibility = View.GONE - } +// if (!adView.isLoading) { +// this.visibility = View.GONE +// } } } diff --git a/wear/build.gradle b/wear/build.gradle index 3e56e6eb..7af00e13 100644 --- a/wear/build.gradle +++ b/wear/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { // versionCode and versionName must be hardcoded to support F-droid - versionCode 805021 - versionName '8.5.2' + versionCode 805041 + versionName '8.5.4' applicationId 'dev.lucasnlm.antimine' minSdkVersion 23 targetSdkVersion 30