diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/DonationDialogHandler.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/DonationDialogHandler.kt index 1217f519e..65c6a100c 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/DonationDialogHandler.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/DonationDialogHandler.kt @@ -19,11 +19,12 @@ package org.kiwix.kiwixmobile.core.utils import android.app.Activity +import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.getPackageInformation import org.kiwix.kiwixmobile.core.dao.NewBookDao +import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp import javax.inject.Inject -const val THREE_DAYS_IN_MILLISECONDS = 3 * 24 * 60 * 60 * 1000L const val THREE_MONTHS_IN_MILLISECONDS = 90 * 24 * 60 * 60 * 1000L class DonationDialogHandler @Inject constructor( @@ -41,26 +42,35 @@ class DonationDialogHandler @Inject constructor( suspend fun attemptToShowDonationPopup() { val currentMilliSeconds = System.currentTimeMillis() val lastPopupMillis = sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds - val timeDifference = currentMilliSeconds - lastPopupMillis - if (shouldShowInitialPopup(lastPopupMillis) || timeDifference >= THREE_MONTHS_IN_MILLISECONDS) { - if (isZimFilesAvailableInLibrary() && isTimeToShowDonation(currentMilliSeconds)) { - showDonationDialogCallback?.showDonationDialog() - resetDonateLater() - } + + val shouldShowPopup = (lastPopupMillis == 0L && shouldShowInitialPopup(currentMilliSeconds)) || + isThreeMonthsElapsed(currentMilliSeconds, lastPopupMillis) + + if (shouldShowPopup && + isZimFilesAvailableInLibrary() && + isTimeToShowDonation(currentMilliSeconds) + ) { + showDonationDialogCallback?.showDonationDialog() + resetDonateLater() } } - private suspend fun shouldShowInitialPopup(lastPopupMillis: Long): Boolean = - lastPopupMillis == 0L && isZimFilesAvailableInLibrary() + fun shouldShowInitialPopup(currentMillis: Long): Boolean { + val appInstallTime = + activity.packageManager.getPackageInformation(activity.packageName, ZERO).firstInstallTime + return isThreeMonthsElapsed(currentMillis, appInstallTime) + } - private fun isTimeToShowDonation(currentMillis: Long): Boolean = - isLaterNotClicked() || isLaterPeriodOver(currentMillis) + fun isTimeToShowDonation(currentMillis: Long): Boolean { + val lastLaterClick = sharedPreferenceUtil.laterClickedMilliSeconds + return lastLaterClick == 0L || + isThreeMonthsElapsed(currentMillis, lastLaterClick) + } - private fun isLaterNotClicked(): Boolean = sharedPreferenceUtil.laterClickedMilliSeconds == 0L - - private fun isLaterPeriodOver(currentMillis: Long): Boolean { - val timeDifference = currentMillis - sharedPreferenceUtil.laterClickedMilliSeconds - return timeDifference >= THREE_DAYS_IN_MILLISECONDS + fun isThreeMonthsElapsed(currentMilliSeconds: Long, lastPopupMillis: Long): Boolean { + if (lastPopupMillis == 0L) return false + val timeDifference = currentMilliSeconds - lastPopupMillis + return timeDifference >= THREE_MONTHS_IN_MILLISECONDS } suspend fun isZimFilesAvailableInLibrary(): Boolean = diff --git a/core/src/test/java/org/kiwix/kiwixmobile/core/utils/DonationDialogHandlerTest.kt b/core/src/test/java/org/kiwix/kiwixmobile/core/utils/DonationDialogHandlerTest.kt index bfa928709..5fee8e651 100644 --- a/core/src/test/java/org/kiwix/kiwixmobile/core/utils/DonationDialogHandlerTest.kt +++ b/core/src/test/java/org/kiwix/kiwixmobile/core/utils/DonationDialogHandlerTest.kt @@ -19,11 +19,15 @@ package org.kiwix.kiwixmobile.core.utils import android.app.Activity +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import io.mockk.Called import io.mockk.Runs import io.mockk.coEvery import io.mockk.every import io.mockk.just import io.mockk.mockk +import io.mockk.spyk import io.mockk.verify import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest @@ -31,7 +35,9 @@ import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.getPackageInformation import org.kiwix.kiwixmobile.core.dao.NewBookDao +import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions @ExperimentalCoroutinesApi @@ -41,10 +47,14 @@ class DonationDialogHandlerTest { private lateinit var newBookDao: NewBookDao private lateinit var donationDialogHandler: DonationDialogHandler private lateinit var showDonationDialogCallback: DonationDialogHandler.ShowDonationDialogCallback + private lateinit var packageManager: PackageManager @BeforeEach fun setup() { activity = mockk(relaxed = true) + packageManager = mockk(relaxed = true) + every { activity.packageManager } returns packageManager + every { activity.packageName } returns "org.kiwix.kiwixmobile" sharedPreferenceUtil = mockk(relaxed = true) newBookDao = mockk(relaxed = true) showDonationDialogCallback = mockk(relaxed = true) @@ -54,15 +64,51 @@ class DonationDialogHandlerTest { } @Test - fun `test should show initial popup`() = runTest { + fun `should show initial donation popup when app is three month old`() = runTest { + donationDialogHandler = spyk(donationDialogHandler) every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds } returns 0L + every { sharedPreferenceUtil.laterClickedMilliSeconds } returns 0L coEvery { newBookDao.getBooks() } returns listOf(mockk()) + every { + donationDialogHandler.shouldShowInitialPopup(any()) + } returns true donationDialogHandler.attemptToShowDonationPopup() verify { showDonationDialogCallback.showDonationDialog() } } @Test - fun `test should not show popup when time difference is less than 3 months`() = runTest { + fun `should not show donation popup if app is not three month old`() = runTest { + every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds } returns 0L + coEvery { newBookDao.getBooks() } returns listOf(mockk()) + val currentMillis = System.currentTimeMillis() + val installTime = currentMillis - 1000 + val packageInfo = PackageInfo().apply { + firstInstallTime = installTime + } + every { + packageManager.getPackageInformation(activity.packageName, ZERO) + } returns packageInfo + donationDialogHandler.attemptToShowDonationPopup() + verify { showDonationDialogCallback wasNot Called } + } + + @Test + fun `should not show donation popup when no ZIM files available in library`() = runTest { + every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds } returns 0L + coEvery { newBookDao.getBooks() } returns emptyList() + val currentMillis = System.currentTimeMillis() + val threeMonthsAgo = currentMillis - THREE_MONTHS_IN_MILLISECONDS + val packageInfo = PackageInfo().apply { + firstInstallTime = threeMonthsAgo + } + + every { packageManager.getPackageInformation(activity.packageName, ZERO) } returns packageInfo + donationDialogHandler.attemptToShowDonationPopup() + verify { showDonationDialogCallback wasNot Called } + } + + @Test + fun `should not show popup if time since last popup is less than three month`() = runTest { val currentMilliSeconds = System.currentTimeMillis() every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds @@ -73,7 +119,7 @@ class DonationDialogHandlerTest { } @Test - fun `test should show popup when time difference is more than 3 months`() = runTest { + fun `should show donation popup if time since last popup exceeds three months`() = runTest { val currentMilliSeconds = System.currentTimeMillis() every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds @@ -84,7 +130,39 @@ class DonationDialogHandlerTest { } @Test - fun `test donate later saves the correct time`() { + fun `test should show donation popup when later clicked time exceeds three months`() = runTest { + donationDialogHandler = spyk(donationDialogHandler) + val currentMilliSeconds = System.currentTimeMillis() + every { + sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds + } returns 0L + every { donationDialogHandler.shouldShowInitialPopup(any()) } returns true + coEvery { newBookDao.getBooks() } returns listOf(mockk()) + every { + sharedPreferenceUtil.laterClickedMilliSeconds + } returns currentMilliSeconds - (THREE_MONTHS_IN_MILLISECONDS + 1000) + donationDialogHandler.attemptToShowDonationPopup() + verify { showDonationDialogCallback.showDonationDialog() } + } + + @Test + fun `test should show popup if later clicked time is less than three months`() = runTest { + donationDialogHandler = spyk(donationDialogHandler) + val currentMilliSeconds = System.currentTimeMillis() + every { + sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds + } returns 0L + every { donationDialogHandler.shouldShowInitialPopup(any()) } returns true + coEvery { newBookDao.getBooks() } returns listOf(mockk()) + every { + sharedPreferenceUtil.laterClickedMilliSeconds + } returns currentMilliSeconds - 10000L + donationDialogHandler.attemptToShowDonationPopup() + verify { showDonationDialogCallback wasNot Called } + } + + @Test + fun `donate later saves the correct time`() { val currentMilliSeconds = System.currentTimeMillis() every { sharedPreferenceUtil.laterClickedMilliSeconds = any() } just Runs donationDialogHandler.donateLater(currentMilliSeconds) @@ -92,14 +170,55 @@ class DonationDialogHandlerTest { } @Test - fun `test reset donate later sets value to zero`() { + fun `reset donate later sets value to zero`() { every { sharedPreferenceUtil.laterClickedMilliSeconds = 0L } just Runs donationDialogHandler.resetDonateLater() verify { sharedPreferenceUtil.laterClickedMilliSeconds = 0L } } @Test - fun `test isZimFilesAvailableInLibrary returns true when isCustomApp is true`() = runTest { + fun `updateLastDonationPopupShownTime sets correct time`() { + every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds = any() } just Runs + val currentTime = System.currentTimeMillis() + donationDialogHandler.updateLastDonationPopupShownTime() + verify { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds = more(currentTime - 1000) } + } + + @Test + fun `isTimeToShowDonation should returns false when laterClicked time is recent`() { + val currentMillis = System.currentTimeMillis() + every { sharedPreferenceUtil.laterClickedMilliSeconds } returns currentMillis - 1000 + val result = donationDialogHandler.isTimeToShowDonation(currentMillis) + assertFalse(result) + } + + @Test + fun `test isTimeToShowDonation should returns true if laterClicked time is over three month`() { + val currentMillis = System.currentTimeMillis() + every { + sharedPreferenceUtil.laterClickedMilliSeconds + } returns currentMillis - THREE_MONTHS_IN_MILLISECONDS + val result = donationDialogHandler.isTimeToShowDonation(currentMillis) + assertTrue(result) + } + + @Test + fun `isThreeMonthsElapsed should return false when lastPopupMillis is zero`() { + val currentMillis = System.currentTimeMillis() + val result = donationDialogHandler.isThreeMonthsElapsed(currentMillis, 0L) + assertFalse(result) + } + + @Test + fun `isThreeMonthsElapsed returns true when lastPopup shows three month before`() { + val currentMillis = System.currentTimeMillis() + val lastPopupMillis = currentMillis - THREE_MONTHS_IN_MILLISECONDS + val result = donationDialogHandler.isThreeMonthsElapsed(currentMillis, lastPopupMillis) + assertTrue(result) + } + + @Test + fun `isZimFilesAvailableInLibrary returns true when isCustomApp is true`() = runTest { with(mockk()) { every { activity.packageName } returns "org.kiwix.kiwixcustom" every { activity.isCustomApp() } returns true @@ -109,7 +228,7 @@ class DonationDialogHandlerTest { } @Test - fun `test isZimFilesAvailableInLibrary returns false when no books and isCustomApp is false`() = + fun `isZimFilesAvailableInLibrary returns false when no books and isCustomApp is false`() = runTest { with(mockk()) { every { activity.packageName } returns "org.kiwix.kiwixmobile"