forked from github/wulkanowy-mirror
Add ads to dashboard (#1815)
This commit is contained in:
parent
c808bf2e61
commit
d8f644c5b4
@ -43,6 +43,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
|
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
|
||||||
|
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "null"
|
||||||
|
|
||||||
if (System.env.SET_BUILD_TIMESTAMP) {
|
if (System.env.SET_BUILD_TIMESTAMP) {
|
||||||
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
||||||
@ -99,6 +100,8 @@ android {
|
|||||||
admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
|
admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
|
||||||
]
|
]
|
||||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
|
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
|
||||||
|
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "\"${System.getenv("DASHBOARD_TILE_AD_ID") ?: "ca-app-pub-3940256099942544/6300978111"}\""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fdroid {
|
fdroid {
|
||||||
|
28
app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
28
app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class AdsHelper @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
preferencesRepository.isAdsEnabled = false
|
||||||
|
preferencesRepository.isAgreeToProcessData = false
|
||||||
|
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("RedundantSuspendModifier", "UNUSED_PARAMETER")
|
||||||
|
suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
|
||||||
|
throw IllegalStateException("Can't get ad banner (F-droid)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AdBanner(val view: View)
|
28
app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
28
app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class AdsHelper @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
preferencesRepository.isAdsEnabled = false
|
||||||
|
preferencesRepository.isAgreeToProcessData = false
|
||||||
|
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("RedundantSuspendModifier", "UNUSED_PARAMETER")
|
||||||
|
suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
|
||||||
|
throw IllegalStateException("Can't get ad banner (HMS)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AdBanner(val view: View)
|
@ -31,10 +31,14 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var analyticsHelper: AnalyticsHelper
|
lateinit var analyticsHelper: AnalyticsHelper
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var adsHelper: AdsHelper
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
initializeAppLanguage()
|
initializeAppLanguage()
|
||||||
themeManager.applyDefaultTheme()
|
themeManager.applyDefaultTheme()
|
||||||
|
adsHelper.initialize()
|
||||||
initLogging()
|
initLogging()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,16 +222,14 @@ class PreferencesRepository @Inject constructor(
|
|||||||
get() = selectedDashboardTilesPreference.asFlow()
|
get() = selectedDashboardTilesPreference.asFlow()
|
||||||
.map { set ->
|
.map { set ->
|
||||||
set.map { DashboardItem.Tile.valueOf(it) }
|
set.map { DashboardItem.Tile.valueOf(it) }
|
||||||
.plus(DashboardItem.Tile.ACCOUNT)
|
.plus(listOf(DashboardItem.Tile.ACCOUNT, DashboardItem.Tile.ADMIN_MESSAGE))
|
||||||
.plus(DashboardItem.Tile.ADMIN_MESSAGE)
|
|
||||||
.toSet()
|
.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedDashboardTiles: Set<DashboardItem.Tile>
|
var selectedDashboardTiles: Set<DashboardItem.Tile>
|
||||||
get() = selectedDashboardTilesPreference.get()
|
get() = selectedDashboardTilesPreference.get()
|
||||||
.map { DashboardItem.Tile.valueOf(it) }
|
.map { DashboardItem.Tile.valueOf(it) }
|
||||||
.plus(DashboardItem.Tile.ACCOUNT)
|
.plus(listOf(DashboardItem.Tile.ACCOUNT, DashboardItem.Tile.ADMIN_MESSAGE))
|
||||||
.plus(DashboardItem.Tile.ADMIN_MESSAGE)
|
|
||||||
.toSet()
|
.toSet()
|
||||||
set(value) {
|
set(value) {
|
||||||
val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
|
val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
|
||||||
@ -271,7 +269,33 @@ class PreferencesRepository @Inject constructor(
|
|||||||
|
|
||||||
var isAppReviewDone: Boolean
|
var isAppReviewDone: Boolean
|
||||||
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
|
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
|
||||||
set(value) = sharedPref.edit().putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value).apply()
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value) }
|
||||||
|
|
||||||
|
var isAppSupportShown: Boolean
|
||||||
|
get() = sharedPref.getBoolean(PREF_KEY_APP_SUPPORT_SHOWN, false)
|
||||||
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_APP_SUPPORT_SHOWN, value) }
|
||||||
|
|
||||||
|
var isAgreeToProcessData: Boolean
|
||||||
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_ads_consent_data_processing,
|
||||||
|
R.bool.pref_default_ads_consent_data_processing
|
||||||
|
)
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putBoolean(context.getString(R.string.pref_key_ads_consent_data_processing), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isPersonalizedAdsEnabled: Boolean
|
||||||
|
get() = sharedPref.getBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, false)
|
||||||
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, value) }
|
||||||
|
|
||||||
|
var isAdsEnabled: Boolean
|
||||||
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_ads_enabled,
|
||||||
|
R.bool.pref_default_ads_enabled
|
||||||
|
)
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
|
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
|
||||||
|
|
||||||
@ -301,6 +325,10 @@ class PreferencesRepository @Inject constructor(
|
|||||||
|
|
||||||
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
|
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
|
||||||
|
|
||||||
|
private const val PREF_KEY_APP_SUPPORT_SHOWN = "app_support_shown"
|
||||||
|
|
||||||
|
private const val PREF_KEY_PERSONALIZED_ADS_ENABLED = "personalized_ads_enabled"
|
||||||
|
|
||||||
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
|
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import io.github.wulkanowy.ui.base.BaseFragment
|
|||||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
||||||
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
|
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
|
||||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||||
@ -47,6 +48,14 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
override var subtitleString =
|
override var subtitleString =
|
||||||
LocalDate.now().toFormattedString("EEEE, d MMMM yyyy").capitalise()
|
LocalDate.now().toFormattedString("EEEE, d MMMM yyyy").capitalise()
|
||||||
|
|
||||||
|
override val tileWidth: Int
|
||||||
|
get() {
|
||||||
|
val recyclerWidth = binding.dashboardRecycler.width
|
||||||
|
val margin = requireContext().dpToPx(24f).toInt()
|
||||||
|
|
||||||
|
return ((recyclerWidth - margin) / resources.displayMetrics.density).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newInstance() = DashboardFragment()
|
fun newInstance() = DashboardFragment()
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.db.entities.Conference
|
|
||||||
import io.github.wulkanowy.data.db.entities.Exam
|
|
||||||
import io.github.wulkanowy.data.db.entities.Grade
|
|
||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||||
|
import io.github.wulkanowy.utils.AdBanner
|
||||||
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
|
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
|
||||||
|
|
||||||
sealed class DashboardItem(val type: Type) {
|
sealed class DashboardItem(val type: Type) {
|
||||||
@ -106,17 +102,26 @@ sealed class DashboardItem(val type: Type) {
|
|||||||
override val isDataLoaded get() = conferences != null
|
override val isDataLoaded get() = conferences != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Ads(
|
||||||
|
val adBanner: AdBanner? = null,
|
||||||
|
override val error: Throwable? = null,
|
||||||
|
override val isLoading: Boolean = false
|
||||||
|
) : DashboardItem(Type.ADS) {
|
||||||
|
|
||||||
|
override val isDataLoaded get() = adBanner != null
|
||||||
|
}
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
ADMIN_MESSAGE,
|
ADMIN_MESSAGE,
|
||||||
ACCOUNT,
|
ACCOUNT,
|
||||||
HORIZONTAL_GROUP,
|
HORIZONTAL_GROUP,
|
||||||
LESSONS,
|
LESSONS,
|
||||||
|
ADS,
|
||||||
GRADES,
|
GRADES,
|
||||||
HOMEWORK,
|
HOMEWORK,
|
||||||
ANNOUNCEMENTS,
|
ANNOUNCEMENTS,
|
||||||
EXAMS,
|
EXAMS,
|
||||||
CONFERENCES,
|
CONFERENCES,
|
||||||
ADS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Tile {
|
enum class Tile {
|
||||||
@ -126,12 +131,12 @@ sealed class DashboardItem(val type: Type) {
|
|||||||
MESSAGES,
|
MESSAGES,
|
||||||
ATTENDANCE,
|
ATTENDANCE,
|
||||||
LESSONS,
|
LESSONS,
|
||||||
|
ADS,
|
||||||
GRADES,
|
GRADES,
|
||||||
HOMEWORK,
|
HOMEWORK,
|
||||||
ANNOUNCEMENTS,
|
ANNOUNCEMENTS,
|
||||||
EXAMS,
|
EXAMS,
|
||||||
CONFERENCES,
|
CONFERENCES,
|
||||||
ADS
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,4 +153,4 @@ fun DashboardItem.Tile.toDashboardItemType() = when (this) {
|
|||||||
DashboardItem.Tile.EXAMS -> DashboardItem.Type.EXAMS
|
DashboardItem.Tile.EXAMS -> DashboardItem.Type.EXAMS
|
||||||
DashboardItem.Tile.CONFERENCES -> DashboardItem.Type.CONFERENCES
|
DashboardItem.Tile.CONFERENCES -> DashboardItem.Type.CONFERENCES
|
||||||
DashboardItem.Tile.ADS -> DashboardItem.Type.ADS
|
DashboardItem.Tile.ADS -> DashboardItem.Type.ADS
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ package io.github.wulkanowy.ui.modules.dashboard
|
|||||||
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import java.util.Collections
|
import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class DashboardItemMoveCallback(
|
class DashboardItemMoveCallback(
|
||||||
private val dashboardAdapter: DashboardAdapter,
|
private val dashboardAdapter: DashboardAdapter,
|
||||||
|
@ -8,6 +8,7 @@ import io.github.wulkanowy.data.enums.MessageFolder
|
|||||||
import io.github.wulkanowy.data.repositories.*
|
import io.github.wulkanowy.data.repositories.*
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import io.github.wulkanowy.utils.calculatePercentage
|
import io.github.wulkanowy.utils.calculatePercentage
|
||||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
@ -31,7 +32,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private val conferenceRepository: ConferenceRepository,
|
private val conferenceRepository: ConferenceRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
|
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
|
||||||
private val adminMessageRepository: AdminMessageRepository
|
private val adminMessageRepository: AdminMessageRepository,
|
||||||
|
private val adsHelper: AdsHelper
|
||||||
) : BasePresenter<DashboardView>(errorHandler, studentRepository) {
|
) : BasePresenter<DashboardView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
private val dashboardItemLoadedList = mutableListOf<DashboardItem>()
|
private val dashboardItemLoadedList = mutableListOf<DashboardItem>()
|
||||||
@ -166,7 +168,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
DashboardItem.Type.CONFERENCES -> {
|
DashboardItem.Type.CONFERENCES -> {
|
||||||
loadConferences(student, forceRefresh)
|
loadConferences(student, forceRefresh)
|
||||||
}
|
}
|
||||||
DashboardItem.Type.ADS -> TODO()
|
DashboardItem.Type.ADS -> loadAds(forceRefresh)
|
||||||
DashboardItem.Type.ADMIN_MESSAGE -> loadAdminMessage(student, forceRefresh)
|
DashboardItem.Type.ADMIN_MESSAGE -> loadAdminMessage(student, forceRefresh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,6 +597,23 @@ class DashboardPresenter @Inject constructor(
|
|||||||
.launchWithUniqueRefreshJob("dashboard_admin_messages", forceRefresh)
|
.launchWithUniqueRefreshJob("dashboard_admin_messages", forceRefresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadAds(forceRefresh: Boolean) {
|
||||||
|
presenterScope.launch {
|
||||||
|
if (!forceRefresh) {
|
||||||
|
updateData(DashboardItem.Ads(), forceRefresh)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dashboardAdItem =
|
||||||
|
runCatching {
|
||||||
|
DashboardItem.Ads(adsHelper.getDashboardTileAdBanner(view!!.tileWidth))
|
||||||
|
}
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
.getOrElse { DashboardItem.Ads(error = it) }
|
||||||
|
|
||||||
|
updateData(dashboardAdItem, forceRefresh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
||||||
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
||||||
val isFirstRunDataLoadedError =
|
val isFirstRunDataLoadedError =
|
||||||
@ -619,6 +638,18 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dashboardItem is DashboardItem.Ads) {
|
||||||
|
if (!dashboardItem.isDataLoaded) {
|
||||||
|
dashboardItemsToLoad = dashboardItemsToLoad - DashboardItem.Type.ADS
|
||||||
|
dashboardTileLoadedList = dashboardTileLoadedList - DashboardItem.Tile.ADS
|
||||||
|
|
||||||
|
dashboardItemLoadedList.removeAll { it.type == DashboardItem.Type.ADS }
|
||||||
|
} else {
|
||||||
|
dashboardItemsToLoad = dashboardItemsToLoad + DashboardItem.Type.ADS
|
||||||
|
dashboardTileLoadedList = dashboardTileLoadedList + DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (forceRefresh) {
|
if (forceRefresh) {
|
||||||
updateForceRefreshData(dashboardItem)
|
updateForceRefreshData(dashboardItem)
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,6 +4,8 @@ import io.github.wulkanowy.ui.base.BaseView
|
|||||||
|
|
||||||
interface DashboardView : BaseView {
|
interface DashboardView : BaseView {
|
||||||
|
|
||||||
|
val tileWidth: Int
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<DashboardItem>)
|
fun updateData(data: List<DashboardItem>)
|
||||||
@ -27,4 +29,4 @@ interface DashboardView : BaseView {
|
|||||||
fun openNotificationsCenterView()
|
fun openNotificationsCenterView()
|
||||||
|
|
||||||
fun openInternetBrowser(url: String)
|
fun openInternetBrowser(url: String)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
@ -22,24 +22,15 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
|
import io.github.wulkanowy.databinding.*
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAdminMessageBinding
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAnnouncementsBinding
|
import io.github.wulkanowy.utils.*
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardConferencesBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardExamsBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardGradesBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardHomeworkBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardHorizontalGroupBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardLessonsBinding
|
|
||||||
import io.github.wulkanowy.utils.createNameInitialsDrawable
|
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
|
||||||
import io.github.wulkanowy.utils.left
|
|
||||||
import io.github.wulkanowy.utils.nickOrName
|
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.*
|
import java.time.Duration
|
||||||
import java.util.Timer
|
import java.time.Instant
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.concurrent.timer
|
import kotlin.concurrent.timer
|
||||||
|
|
||||||
@ -120,6 +111,9 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
||||||
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false)
|
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
DashboardItem.Type.ADS.ordinal -> AdsViewHolder(
|
||||||
|
ItemDashboardAdsBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
else -> throw IllegalArgumentException()
|
else -> throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,6 +129,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
||||||
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
||||||
is AdminMessageViewHolder -> bindAdminMessage(holder, position)
|
is AdminMessageViewHolder -> bindAdminMessage(holder, position)
|
||||||
|
is AdsViewHolder -> bindAdsViewHolder(holder, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,6 +741,20 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun bindAdsViewHolder(adsViewHolder: AdsViewHolder, position: Int) {
|
||||||
|
val item = (items[position] as DashboardItem.Ads).adBanner ?: return
|
||||||
|
val binding = adsViewHolder.binding
|
||||||
|
|
||||||
|
binding.dashboardAdminMessageItemContent.removeAllViews()
|
||||||
|
binding.dashboardAdminMessageItemContent.addView(
|
||||||
|
item.view,
|
||||||
|
ViewGroup.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class AccountViewHolder(val binding: ItemDashboardAccountBinding) :
|
class AccountViewHolder(val binding: ItemDashboardAccountBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
@ -788,6 +797,9 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
class AdminMessageViewHolder(val binding: ItemDashboardAdminMessageBinding) :
|
class AdminMessageViewHolder(val binding: ItemDashboardAdminMessageBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
|
class AdsViewHolder(val binding: ItemDashboardAdsBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
private class DiffCallback(
|
private class DiffCallback(
|
||||||
private val newList: List<DashboardItem>,
|
private val newList: List<DashboardItem>,
|
||||||
private val oldList: List<DashboardItem>
|
private val oldList: List<DashboardItem>
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -33,4 +33,4 @@ class DashboardAnnouncementsAdapter :
|
|||||||
|
|
||||||
class ViewHolder(val binding: SubitemDashboardAnnouncementsBinding) :
|
class ViewHolder(val binding: SubitemDashboardAnnouncementsBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -33,4 +33,4 @@ class DashboardConferencesAdapter :
|
|||||||
|
|
||||||
class ViewHolder(val binding: SubitemDashboardConferencesBinding) :
|
class ViewHolder(val binding: SubitemDashboardConferencesBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -56,4 +56,4 @@ class DashboardExamsAdapter :
|
|||||||
|
|
||||||
class ViewHolder(val binding: SubitemDashboardExamsBinding) :
|
class ViewHolder(val binding: SubitemDashboardExamsBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -53,4 +53,4 @@ class DashboardHomeworkAdapter : RecyclerView.Adapter<DashboardHomeworkAdapter.V
|
|||||||
|
|
||||||
class ViewHolder(val binding: SubitemDashboardHomeworkBinding) :
|
class ViewHolder(val binding: SubitemDashboardHomeworkBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.elevation.ElevationOverlayProvider
|
import com.google.android.material.elevation.ElevationOverlayProvider
|
||||||
import com.ncapdevi.fragnav.FragNavController
|
import com.ncapdevi.fragnav.FragNavController
|
||||||
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
||||||
@ -20,6 +21,7 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.ActivityMainBinding
|
import io.github.wulkanowy.databinding.ActivityMainBinding
|
||||||
|
import io.github.wulkanowy.databinding.DialogAdsConsentBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||||
@ -288,6 +290,50 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
inAppReviewHelper.showInAppReview(this)
|
inAppReviewHelper.showInAppReview(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showAppSupport() {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.main_support_title)
|
||||||
|
.setMessage(R.string.main_support_description)
|
||||||
|
.setPositiveButton(R.string.main_support_positive) { _, _ -> presenter.onEnableAdsSelected() }
|
||||||
|
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||||
|
.setOnDismissListener { }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showPrivacyPolicyDialog() {
|
||||||
|
val dialogAdsConsentBinding = DialogAdsConsentBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
val dialog = MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.pref_ads_consent_title)
|
||||||
|
.setMessage(R.string.pref_ads_consent_description)
|
||||||
|
.setView(dialogAdsConsentBinding.root)
|
||||||
|
.show()
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentOver.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
dialogAdsConsentBinding.adsConsentPersonalised.isEnabled = isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentPersonalised.setOnClickListener {
|
||||||
|
presenter.onPrivacyAgree(true)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentNonPersonalised.setOnClickListener {
|
||||||
|
presenter.onPrivacyAgree(false)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentPrivacy.setOnClickListener { presenter.onPrivacySelected() }
|
||||||
|
dialogAdsConsentBinding.adsConsentCancel.setOnClickListener { dialog.cancel() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openPrivacyPolicy() {
|
||||||
|
openInternetBrowser(
|
||||||
|
"https://wulkanowy.github.io/polityka-prywatnosci.html",
|
||||||
|
::showMessage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
navController.onSaveInstanceState(outState)
|
navController.onSaveInstanceState(outState)
|
||||||
|
@ -14,11 +14,15 @@ import io.github.wulkanowy.ui.base.ErrorHandler
|
|||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.account.AccountView
|
import io.github.wulkanowy.ui.modules.account.AccountView
|
||||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsView
|
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsView
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeView
|
import io.github.wulkanowy.ui.modules.grade.GradeView
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageView
|
import io.github.wulkanowy.ui.modules.message.MessageView
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
|
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
|
||||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||||
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -29,10 +33,12 @@ import javax.inject.Inject
|
|||||||
class MainPresenter @Inject constructor(
|
class MainPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val prefRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val syncManager: SyncManager,
|
private val syncManager: SyncManager,
|
||||||
private val analytics: AnalyticsHelper,
|
private val analytics: AnalyticsHelper,
|
||||||
private val json: Json
|
private val json: Json,
|
||||||
|
private val adsHelper: AdsHelper,
|
||||||
|
private val appInfo: AppInfo
|
||||||
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
||||||
@ -47,7 +53,7 @@ class MainPresenter @Inject constructor(
|
|||||||
|
|
||||||
private val Destination?.startMenuIndex
|
private val Destination?.startMenuIndex
|
||||||
get() = when {
|
get() = when {
|
||||||
this == null -> prefRepository.startMenuIndex
|
this == null -> preferencesRepository.startMenuIndex
|
||||||
destinationType in rootDestinationTypeList -> {
|
destinationType in rootDestinationTypeList -> {
|
||||||
rootDestinationTypeList.indexOf(destinationType)
|
rootDestinationTypeList.indexOf(destinationType)
|
||||||
}
|
}
|
||||||
@ -71,6 +77,8 @@ class MainPresenter @Inject constructor(
|
|||||||
|
|
||||||
syncManager.startPeriodicSyncWorker()
|
syncManager.startPeriodicSyncWorker()
|
||||||
|
|
||||||
|
checkAppSupport()
|
||||||
|
|
||||||
analytics.logEvent("app_open", "destination" to initDestination.toString())
|
analytics.logEvent("app_open", "destination" to initDestination.toString())
|
||||||
Timber.i("Main view was initialized with $initDestination")
|
Timber.i("Main view was initialized with $initDestination")
|
||||||
}
|
}
|
||||||
@ -155,18 +163,53 @@ class MainPresenter @Inject constructor(
|
|||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInAppReview() {
|
fun onEnableAdsSelected() {
|
||||||
prefRepository.inAppReviewCount++
|
view?.showPrivacyPolicyDialog()
|
||||||
|
}
|
||||||
|
|
||||||
if (prefRepository.inAppReviewDate == null) {
|
fun onPrivacyAgree(isPersonalizedAds: Boolean) {
|
||||||
prefRepository.inAppReviewDate = Instant.now()
|
preferencesRepository.isAdsEnabled = true
|
||||||
|
preferencesRepository.isAgreeToProcessData = true
|
||||||
|
preferencesRepository.isPersonalizedAdsEnabled = isPersonalizedAds
|
||||||
|
|
||||||
|
adsHelper.initialize()
|
||||||
|
|
||||||
|
preferencesRepository.selectedDashboardTiles += DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPrivacySelected() {
|
||||||
|
view?.openPrivacyPolicy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkInAppReview() {
|
||||||
|
preferencesRepository.inAppReviewCount++
|
||||||
|
|
||||||
|
if (preferencesRepository.inAppReviewDate == null) {
|
||||||
|
preferencesRepository.inAppReviewDate = Instant.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prefRepository.isAppReviewDone && prefRepository.inAppReviewCount >= 50 &&
|
if (!preferencesRepository.isAppReviewDone && preferencesRepository.inAppReviewCount >= 50 &&
|
||||||
Instant.now().minus(Duration.ofDays(14)).isAfter(prefRepository.inAppReviewDate)
|
Instant.now().minus(Duration.ofDays(14)).isAfter(preferencesRepository.inAppReviewDate)
|
||||||
) {
|
) {
|
||||||
view?.showInAppReview()
|
view?.showInAppReview()
|
||||||
prefRepository.isAppReviewDone = true
|
preferencesRepository.isAppReviewDone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkAppSupport() {
|
||||||
|
if (!preferencesRepository.isAppSupportShown && !preferencesRepository.isAdsEnabled
|
||||||
|
&& appInfo.buildFlavor == "play"
|
||||||
|
) {
|
||||||
|
presenterScope.launch {
|
||||||
|
val student = runCatching { studentRepository.getCurrentStudent(false) }
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
.getOrElse { return@launch }
|
||||||
|
|
||||||
|
if (Instant.now().minus(Duration.ofDays(28)).isAfter(student.registrationDate)) {
|
||||||
|
view?.showAppSupport()
|
||||||
|
preferencesRepository.isAppSupportShown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,12 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
fun showInAppReview()
|
fun showInAppReview()
|
||||||
|
|
||||||
|
fun showAppSupport()
|
||||||
|
|
||||||
|
fun showPrivacyPolicyDialog()
|
||||||
|
|
||||||
|
fun openPrivacyPolicy()
|
||||||
|
|
||||||
fun openMoreDestination(destination: Destination)
|
fun openMoreDestination(destination: Destination)
|
||||||
|
|
||||||
interface MainChildView {
|
interface MainChildView {
|
||||||
|
@ -13,6 +13,7 @@ import androidx.core.graphics.drawable.RoundedBitmapDrawable
|
|||||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
|
||||||
|
|
||||||
@ColorInt
|
@ColorInt
|
||||||
fun Context.getThemeAttrColor(@AttrRes colorAttr: Int): Int {
|
fun Context.getThemeAttrColor(@AttrRes colorAttr: Int): Int {
|
||||||
val array = obtainStyledAttributes(null, intArrayOf(colorAttr))
|
val array = obtainStyledAttributes(null, intArrayOf(colorAttr))
|
||||||
|
79
app/src/main/res/layout/dialog_ads_consent.xml
Normal file
79
app/src/main/res/layout/dialog_ads_consent.xml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ads_consent_privacy"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:text="Privacy Policy"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/ads_consent_over"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="17dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="I am over 18 years old"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="14dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/ads_consent_privacy" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ads_consent_personalised"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:enabled="false"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="Yes, personalized ads"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/ads_consent_over" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ads_consent_non_personalised"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="Yes, non-personalized ads"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/ads_consent_cancel"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/ads_consent_personalised"
|
||||||
|
app:layout_constraintVertical_bias="0" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ads_consent_cancel"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="Cancel"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
15
app/src/main/res/layout/item_dashboard_ads.xml
Normal file
15
app/src/main/res/layout/item_dashboard_ads.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:layout_marginVertical="6dp"
|
||||||
|
app:cardElevation="4dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/dashboard_admin_message_item_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
@ -37,4 +37,6 @@
|
|||||||
<item>GRADES</item>
|
<item>GRADES</item>
|
||||||
<item>ANNOUNCEMENTS</item>
|
<item>ANNOUNCEMENTS</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<bool name="pref_default_ads_enabled">false</bool>
|
||||||
|
<bool name="pref_default_ads_consent_data_processing">false</bool>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -37,4 +37,8 @@
|
|||||||
<string name="pref_key_notifications_piggyback">notifications_piggyback</string>
|
<string name="pref_key_notifications_piggyback">notifications_piggyback</string>
|
||||||
<string name="pref_key_notifications_piggyback_cancel_original">notifications_piggyback_cancel_original</string>
|
<string name="pref_key_notifications_piggyback_cancel_original">notifications_piggyback_cancel_original</string>
|
||||||
<string name="pref_key_ads_single_support">single_ad_support</string>
|
<string name="pref_key_ads_single_support">single_ad_support</string>
|
||||||
|
<string name="pref_key_ads_enabled">ads_enabled</string>
|
||||||
|
<string name="pref_key_ads_privacy_policy">ads_privacy_policy</string>
|
||||||
|
<string name="pref_key_ads_consent_data_processing">ads_consent_data_processing</string>
|
||||||
|
<string name="pref_key_ads_over_eighteen">ads_over_eighteen</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -85,6 +85,9 @@
|
|||||||
<string name="main_log_in">Log in</string>
|
<string name="main_log_in">Log in</string>
|
||||||
<string name="main_session_expired">Session expired</string>
|
<string name="main_session_expired">Session expired</string>
|
||||||
<string name="main_session_relogin">Session expired, log in again</string>
|
<string name="main_session_relogin">Session expired, log in again</string>
|
||||||
|
<string name="main_support_title">Application support</string>
|
||||||
|
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
||||||
|
<string name="main_support_positive">Enable ads</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Grade-->
|
<!--Grade-->
|
||||||
@ -715,6 +718,10 @@
|
|||||||
<string name="pref_ads_privacy_link">Privacy policy</string>
|
<string name="pref_ads_privacy_link">Privacy policy</string>
|
||||||
<string name="pref_ads_loading">Ad is loading</string>
|
<string name="pref_ads_loading">Ad is loading</string>
|
||||||
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
|
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
|
||||||
|
<string name="pref_ads_consent_title">Can we use your data to display ads?</string>
|
||||||
|
<string name="pref_ads_consent_description">You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details</string>
|
||||||
|
<string name="pref_ads_summary_personalized">Personalized ads</string>
|
||||||
|
<string name="pref_ads_summary_non_personalized">Non-personalized ads</string>
|
||||||
|
|
||||||
<string name="pref_settings_advanced_title">Advanced</string>
|
<string name="pref_settings_advanced_title">Advanced</string>
|
||||||
<string name="pref_settings_appearance_title">Appearance & Behavior</string>
|
<string name="pref_settings_appearance_title">Appearance & Behavior</string>
|
||||||
|
@ -2,12 +2,15 @@ package io.github.wulkanowy.ui.modules.settings.ads
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.preference.CheckBoxPreference
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
|
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.databinding.DialogAdsConsentBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.base.ErrorDialog
|
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
@ -36,6 +39,22 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
|
|||||||
presenter.onWatchSingleAdSelected()
|
presenter.onWatchSingleAdSelected()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findPreference<Preference>(getString(R.string.pref_key_ads_privacy_policy))?.setOnPreferenceClickListener {
|
||||||
|
presenter.onPrivacySelected()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference<CheckBoxPreference>(getString(R.string.pref_key_ads_consent_data_processing))
|
||||||
|
?.setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
presenter.onConsentSelected(newValue as Boolean)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference<SwitchPreferenceCompat>(getString(R.string.pref_key_ads_enabled))?.setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
presenter.onAddEnabled(newValue as Boolean)
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showAd(ad: RewardedInterstitialAd) {
|
override fun showAd(ad: RewardedInterstitialAd) {
|
||||||
@ -45,13 +64,50 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showPrivacyPolicyDialog() {
|
override fun showPrivacyPolicyDialog() {
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
val dialogAdsConsentBinding = DialogAdsConsentBinding.inflate(layoutInflater)
|
||||||
.setTitle(getString(R.string.pref_ads_privacy_title))
|
|
||||||
.setMessage(getString(R.string.pref_ads_privacy_description))
|
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||||
.setPositiveButton(getString(R.string.pref_ads_privacy_agree)) { _, _ -> presenter.onAgreedPrivacy() }
|
.setTitle(R.string.pref_ads_consent_title)
|
||||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
.setMessage(R.string.pref_ads_consent_description)
|
||||||
.setNeutralButton(getString(R.string.pref_ads_privacy_link)) { _, _ -> presenter.onPrivacySelected() }
|
.setView(dialogAdsConsentBinding.root)
|
||||||
|
.setOnCancelListener { presenter.onPrivacyDialogCanceled() }
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentOver.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
dialogAdsConsentBinding.adsConsentPersonalised.isEnabled = isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentPersonalised.setOnClickListener {
|
||||||
|
presenter.onPersonalizedAgree()
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentNonPersonalised.setOnClickListener {
|
||||||
|
presenter.onNonPersonalizedAgree()
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentPrivacy.setOnClickListener { presenter.onPrivacySelected() }
|
||||||
|
dialogAdsConsentBinding.adsConsentCancel.setOnClickListener { dialog.cancel() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showProcessingDataSummary(isPersonalized: Boolean?) {
|
||||||
|
val summaryText = isPersonalized?.let {
|
||||||
|
getString(if (it) R.string.pref_ads_summary_personalized else R.string.pref_ads_summary_non_personalized)
|
||||||
|
}
|
||||||
|
|
||||||
|
findPreference<CheckBoxPreference>(getString(R.string.pref_key_ads_consent_data_processing))
|
||||||
|
?.summary = summaryText
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setCheckedProcessingData(checked: Boolean) {
|
||||||
|
findPreference<CheckBoxPreference>(getString(R.string.pref_key_ads_consent_data_processing))
|
||||||
|
?.isChecked = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setCheckedAdsEnabled(checked: Boolean) {
|
||||||
|
findPreference<SwitchPreferenceCompat>(getString(R.string.pref_key_ads_enabled))
|
||||||
|
?.isChecked = checked
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openPrivacyPolicy() {
|
override fun openPrivacyPolicy() {
|
||||||
@ -98,4 +154,4 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
|
|||||||
override fun showErrorDetailsDialog(error: Throwable) {
|
override fun showErrorDetailsDialog(error: Throwable) {
|
||||||
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package io.github.wulkanowy.ui.modules.settings.ads
|
package io.github.wulkanowy.ui.modules.settings.ads
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
import io.github.wulkanowy.utils.AdsHelper
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -11,24 +13,22 @@ import javax.inject.Inject
|
|||||||
class AdsPresenter @Inject constructor(
|
class AdsPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val adsHelper: AdsHelper
|
private val adsHelper: AdsHelper,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
) : BasePresenter<AdsView>(errorHandler, studentRepository) {
|
) : BasePresenter<AdsView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
override fun onAttachView(view: AdsView) {
|
override fun onAttachView(view: AdsView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
Timber.i("Settings ads view was initialized")
|
Timber.i("Settings ads view was initialized")
|
||||||
|
|
||||||
|
view.showProcessingDataSummary(
|
||||||
|
preferencesRepository.isPersonalizedAdsEnabled.takeIf {
|
||||||
|
preferencesRepository.isAgreeToProcessData
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onWatchSingleAdSelected() {
|
fun onWatchSingleAdSelected() {
|
||||||
view?.showPrivacyPolicyDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onPrivacySelected() {
|
|
||||||
view?.openPrivacyPolicy()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onAgreedPrivacy() {
|
|
||||||
view?.showLoadingSupportAd(true)
|
view?.showLoadingSupportAd(true)
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
runCatching { adsHelper.getSupportAd() }
|
runCatching { adsHelper.getSupportAd() }
|
||||||
@ -41,4 +41,48 @@ class AdsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
fun onConsentSelected(isChecked: Boolean) {
|
||||||
|
if (isChecked) {
|
||||||
|
view?.showPrivacyPolicyDialog()
|
||||||
|
} else {
|
||||||
|
view?.showProcessingDataSummary(null)
|
||||||
|
view?.setCheckedAdsEnabled(false)
|
||||||
|
onAddEnabled(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPrivacySelected() {
|
||||||
|
view?.openPrivacyPolicy()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPrivacyDialogCanceled() {
|
||||||
|
view?.setCheckedProcessingData(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNonPersonalizedAgree() {
|
||||||
|
preferencesRepository.isPersonalizedAdsEnabled = false
|
||||||
|
|
||||||
|
adsHelper.initialize()
|
||||||
|
|
||||||
|
view?.setCheckedProcessingData(true)
|
||||||
|
view?.showProcessingDataSummary(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPersonalizedAgree() {
|
||||||
|
preferencesRepository.isPersonalizedAdsEnabled = true
|
||||||
|
|
||||||
|
adsHelper.initialize()
|
||||||
|
|
||||||
|
view?.setCheckedProcessingData(true)
|
||||||
|
view?.showProcessingDataSummary(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAddEnabled(isEnabled: Boolean) {
|
||||||
|
if (isEnabled) {
|
||||||
|
preferencesRepository.selectedDashboardTiles += DashboardItem.Tile.ADS
|
||||||
|
} else {
|
||||||
|
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,4 +16,10 @@ interface AdsView : BaseView {
|
|||||||
fun showLoadingSupportAd(show: Boolean)
|
fun showLoadingSupportAd(show: Boolean)
|
||||||
|
|
||||||
fun showWatchAdOncePerVisit(show: Boolean)
|
fun showWatchAdOncePerVisit(show: Boolean)
|
||||||
}
|
|
||||||
|
fun setCheckedAdsEnabled(checked: Boolean)
|
||||||
|
|
||||||
|
fun setCheckedProcessingData(checked: Boolean)
|
||||||
|
|
||||||
|
fun showProcessingDataSummary(isPersonalized: Boolean?)
|
||||||
|
}
|
||||||
|
@ -2,27 +2,39 @@ package io.github.wulkanowy.utils
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
import com.google.ads.mediation.admob.AdMobAdapter
|
import com.google.ads.mediation.admob.AdMobAdapter
|
||||||
import com.google.android.gms.ads.AdRequest
|
import com.google.android.gms.ads.*
|
||||||
import com.google.android.gms.ads.LoadAdError
|
|
||||||
import com.google.android.gms.ads.MobileAds
|
|
||||||
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
|
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
|
||||||
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoadCallback
|
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoadCallback
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import io.github.wulkanowy.BuildConfig
|
import io.github.wulkanowy.BuildConfig
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
import kotlin.coroutines.suspendCoroutine
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
class AdsHelper @Inject constructor(@ApplicationContext private val context: Context) {
|
|
||||||
|
class AdsHelper @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
if (preferencesRepository.isAgreeToProcessData) {
|
||||||
|
MobileAds.initialize(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getSupportAd(): RewardedInterstitialAd? {
|
suspend fun getSupportAd(): RewardedInterstitialAd? {
|
||||||
MobileAds.initialize(context)
|
|
||||||
|
|
||||||
val extra = Bundle().apply { putString("npa", "1") }
|
val extra = Bundle().apply { putString("npa", "1") }
|
||||||
val adRequest = AdRequest.Builder()
|
val adRequest = AdRequest.Builder()
|
||||||
.addNetworkExtrasBundle(AdMobAdapter::class.java, extra)
|
.apply {
|
||||||
|
if (!preferencesRepository.isPersonalizedAdsEnabled) {
|
||||||
|
addNetworkExtrasBundle(AdMobAdapter::class.java, extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return suspendCoroutine {
|
return suspendCoroutine {
|
||||||
@ -41,4 +53,35 @@ class AdsHelper @Inject constructor(@ApplicationContext private val context: Con
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
|
||||||
|
val extra = Bundle().apply { putString("npa", "1") }
|
||||||
|
val adRequest = AdRequest.Builder()
|
||||||
|
.apply {
|
||||||
|
if (!preferencesRepository.isPersonalizedAdsEnabled) {
|
||||||
|
addNetworkExtrasBundle(AdMobAdapter::class.java, extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return suspendCoroutine {
|
||||||
|
val adView = AdView(context).apply {
|
||||||
|
adSize = AdSize.getPortraitAnchoredAdaptiveBannerAdSize(context, width)
|
||||||
|
adUnitId = BuildConfig.DASHBOARD_TILE_AD_ID
|
||||||
|
adListener = object : AdListener() {
|
||||||
|
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
|
||||||
|
it.resumeWithException(IllegalArgumentException(loadAdError.message))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAdLoaded() {
|
||||||
|
it.resume(AdBanner(this@apply))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adView.loadAd(adRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AdBanner(val view: View)
|
||||||
|
@ -2,11 +2,34 @@
|
|||||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
app:title="@string/pref_ads_support_category_name">
|
app:title="Agreements">
|
||||||
<Preference
|
<Preference
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:key="@string/pref_key_ads_privacy_policy"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:title="Privacy Policy" />
|
||||||
|
<CheckBoxPreference
|
||||||
|
app:defaultValue="@bool/pref_default_ads_consent_data_processing"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:key="@string/pref_key_ads_consent_data_processing"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:title="Consent to processing of data related to ads" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:title="@string/pref_ads_support_category_name">
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:defaultValue="@string/pref_key_ads_enabled"
|
||||||
|
app:dependency="@string/pref_key_ads_consent_data_processing"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:key="@string/pref_key_ads_enabled"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:title="Show ads in app" />
|
||||||
|
<Preference
|
||||||
|
app:dependency="@string/pref_key_ads_consent_data_processing"
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
app:key="@string/pref_key_ads_single_support"
|
app:key="@string/pref_key_ads_single_support"
|
||||||
app:singleLineTitle="false"
|
app:singleLineTitle="false"
|
||||||
app:title="@string/pref_ads_support" />
|
app:title="@string/pref_ads_support" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@ -4,7 +4,9 @@ import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.mockk.*
|
import io.mockk.*
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -31,6 +33,12 @@ class MainPresenterTest {
|
|||||||
@MockK(relaxed = true)
|
@MockK(relaxed = true)
|
||||||
lateinit var analytics: AnalyticsHelper
|
lateinit var analytics: AnalyticsHelper
|
||||||
|
|
||||||
|
@MockK(relaxed = true)
|
||||||
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
@MockK(relaxed = true)
|
||||||
|
lateinit var adsHelper: AdsHelper
|
||||||
|
|
||||||
private lateinit var presenter: MainPresenter
|
private lateinit var presenter: MainPresenter
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@ -42,10 +50,12 @@ class MainPresenterTest {
|
|||||||
presenter = MainPresenter(
|
presenter = MainPresenter(
|
||||||
errorHandler = errorHandler,
|
errorHandler = errorHandler,
|
||||||
studentRepository = studentRepository,
|
studentRepository = studentRepository,
|
||||||
prefRepository = prefRepository,
|
preferencesRepository = prefRepository,
|
||||||
syncManager = syncManager,
|
syncManager = syncManager,
|
||||||
analytics = analytics,
|
analytics = analytics,
|
||||||
json = Json
|
json = Json,
|
||||||
|
appInfo = appInfo,
|
||||||
|
adsHelper = adsHelper
|
||||||
)
|
)
|
||||||
presenter.onAttachView(mainView, null)
|
presenter.onAttachView(mainView, null)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user