1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2025-01-31 13:18:20 +01:00

Add single support advert (#1484)

This commit is contained in:
Rafał Borcz 2021-10-21 10:51:00 +02:00 committed by GitHub
parent 09a134d442
commit 94fd303f8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 324 additions and 59 deletions

View File

@ -29,7 +29,10 @@ android {
resValue "string", "app_name", "Wulkanowy"
manifestPlaceholders = [firebase_enabled: project.hasProperty("enableFirebase")]
manifestPlaceholders = [
firebase_enabled: project.hasProperty("enableFirebase"),
admob_project_id: ""
]
javaCompileOptions {
annotationProcessorOptions {
arguments += [
@ -39,6 +42,8 @@ android {
}
}
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
if (System.env.SET_BUILD_TIMESTAMP) {
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
} else {
@ -82,23 +87,21 @@ android {
productFlavors {
hms {
dimension "platform"
manifestPlaceholders = [
install_channel: "AppGallery"
]
manifestPlaceholders = [install_channel: "AppGallery"]
}
play {
dimension "platform"
manifestPlaceholders = [
install_channel: "Google Play"
install_channel : "Google Play",
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"}\""
}
fdroid {
dimension "platform"
manifestPlaceholders = [
install_channel: "F-Droid"
]
manifestPlaceholders = [install_channel: "F-Droid"]
}
}
@ -233,6 +236,7 @@ dependencies {
playImplementation 'com.google.firebase:firebase-crashlytics:'
playImplementation 'com.google.android.play:core:1.10.2'
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.android.gms:play-services-ads:20.4.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.3.0.301'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.1.200'

View File

@ -165,33 +165,32 @@
<meta-data
android:name="install_channel"
android:value="${install_channel}" />
<meta-data
android:name="firebase_analytics_collection_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="google_analytics_adid_collection_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="firebase_messaging_auto_init_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="firebase_inapp_messaging_auto_data_collection_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_all" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="push_channel" />
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="${admob_project_id}" />
<meta-data
android:name="com.google.android.gms.ads.DELAY_APP_MEASUREMENT_INIT"
android:value="true" />
</application>
</manifest>

View File

@ -82,18 +82,20 @@ class AboutPresenter @Inject constructor(
private fun loadData() {
view?.run {
updateData(listOfNotNull(
versionRes,
creatorsRes,
feedbackRes,
faqRes,
discordRes,
facebookRes,
twitterRes,
homepageRes,
licensesRes,
privacyRes
))
updateData(
listOfNotNull(
versionRes,
creatorsRes,
feedbackRes,
faqRes,
discordRes,
facebookRes,
twitterRes,
homepageRes,
licensesRes,
privacyRes
)
)
}
}
}

View File

@ -299,7 +299,8 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
val currentDayHeader =
timetableFull?.headers.orEmpty().singleOrNull { it.date == currentDate }
val tomorrowTimetable = timetableFull?.lessons.orEmpty()
val tomorrowTimetable = timetableFull?.lessons
.orEmpty()
.filter { it.date == currentDate.plusDays(1) }
.filterNot { it.canceled }
val tomorrowDayHeader =

View File

@ -27,10 +27,6 @@ class AdvancedFragment : PreferenceFragmentCompat(),
@Inject
lateinit var lingver: Lingver
companion object {
fun newInstance() = AdvancedFragment()
}
override val titleStringId get() = R.string.pref_settings_advanced_title
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@ -27,10 +27,6 @@ class AppearanceFragment : PreferenceFragmentCompat(),
@Inject
lateinit var lingver: Lingver
companion object {
fun newInstance() = AppearanceFragment()
}
override val titleStringId get() = R.string.pref_settings_appearance_title
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@ -40,10 +40,6 @@ class NotificationsFragment : PreferenceFragmentCompat(),
@Inject
lateinit var appInfo: AppInfo
companion object {
fun newInstance() = NotificationsFragment()
}
override val titleStringId get() = R.string.pref_settings_notifications_title
override val isNotificationPermissionGranted: Boolean

View File

@ -20,10 +20,6 @@ class SyncFragment : PreferenceFragmentCompat(),
@Inject
lateinit var presenter: SyncPresenter
companion object {
fun newInstance() = SyncFragment()
}
override val titleStringId get() = R.string.pref_settings_sync_title
override val syncSuccessString get() = getString(R.string.pref_services_message_sync_success)

View File

@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18,11c0,0.67 0,1.33 0,2c1.2,0 2.76,0 4,0c0,-0.67 0,-1.33 0,-2C20.76,11 19.2,11 18,11z" />
<path
android:fillColor="@android:color/white"
android:pathData="M16,17.61c0.96,0.71 2.21,1.65 3.2,2.39c0.4,-0.53 0.8,-1.07 1.2,-1.6c-0.99,-0.74 -2.24,-1.68 -3.2,-2.4C16.8,16.54 16.4,17.08 16,17.61z" />
<path
android:fillColor="@android:color/white"
android:pathData="M20.4,5.6C20,5.07 19.6,4.53 19.2,4c-0.99,0.74 -2.24,1.68 -3.2,2.4c0.4,0.53 0.8,1.07 1.2,1.6C18.16,7.28 19.41,6.35 20.4,5.6z" />
<path
android:fillColor="@android:color/white"
android:pathData="M4,9c-1.1,0 -2,0.9 -2,2v2c0,1.1 0.9,2 2,2h1v4h2v-4h1l5,3V6L8,9H4zM9.03,10.71L11,9.53v4.94l-1.97,-1.18L8.55,13H8H4v-2h4h0.55L9.03,10.71z" />
<path
android:fillColor="@android:color/white"
android:pathData="M15.5,12c0,-1.33 -0.58,-2.53 -1.5,-3.35v6.69C14.92,14.53 15.5,13.33 15.5,12z" />
</vector>

View File

@ -34,4 +34,5 @@
<string name="pref_key_message_send_draft">message_send_recipients</string>
<string name="pref_key_last_sync_date">last_sync_date</string>
<string name="pref_key_notifications_piggyback">notifications_piggyback</string>
<string name="pref_key_ads_single_support">single_ad_support</string>
</resources>

View File

@ -658,10 +658,19 @@
<string name="pref_other_fill_message_content">Reply with message history</string>
<string name="pref_other_optional_arithmetic_average">Show arithmetic average when no weights provided</string>
<string name="pref_ads_support_category_name">Support</string>
<string name="pref_ads_support">Watch single ad to support project</string>
<string name="pref_ads_privacy_title">Consent to data processing</string>
<string name="pref_ads_privacy_description">To view an advertisement you must agree to the data processing terms of our Privacy Policy</string>
<string name="pref_ads_privacy_agree">Agree</string>
<string name="pref_ads_privacy_link">Privacy policy</string>
<string name="pref_ads_loading">Ad is loading</string>
<string name="pref_settings_advanced_title">Advanced</string>
<string name="pref_settings_appearance_title">Appearance &amp; Behavior</string>
<string name="pref_settings_notifications_title">Notifications</string>
<string name="pref_settings_sync_title">Synchronization</string>
<string name="pref_settings_ads_title">Advertisements</string>
<string name="pref_grades_appearance_header">Grades</string>
<string name="pref_dashboard_appearance_header">Dashboard</string>
@ -681,6 +690,7 @@
<string name="pref_advanced_category_summary">Plus and minus values, average calculation</string>
<string name="pref_advanced_category">Advanced</string>
<string name="pref_about_category_summary">App version, contributors, social portals, licenses</string>
<string name="pref_ads_category_summary">Displaying advertisements, project support</string>
<!--Notification Channels-->

View File

@ -1,33 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
app:key="appearance"
app:fragment="io.github.wulkanowy.ui.modules.settings.appearance.AppearanceFragment"
app:icon="@drawable/ic_settings_appearance"
app:key="appearance"
app:summary="@string/pref_appearance_category_summary"
app:title="@string/pref_appearance_category"
app:fragment="io.github.wulkanowy.ui.modules.settings.appearance.AppearanceFragment" />
app:title="@string/pref_appearance_category" />
<Preference
app:key="notifications"
app:fragment="io.github.wulkanowy.ui.modules.settings.notifications.NotificationsFragment"
app:icon="@drawable/ic_settings_notifications"
app:key="notifications"
app:summary="@string/pref_notifications_category_summary"
app:title="@string/pref_notifications_category"
app:fragment="io.github.wulkanowy.ui.modules.settings.notifications.NotificationsFragment" />
app:title="@string/pref_notifications_category" />
<Preference
app:key="sync"
app:fragment="io.github.wulkanowy.ui.modules.settings.sync.SyncFragment"
app:icon="@drawable/ic_settings_sync"
app:key="sync"
app:summary="@string/pref_sync_category_summary"
app:title="@string/pref_sync_category"
app:fragment="io.github.wulkanowy.ui.modules.settings.sync.SyncFragment" />
app:title="@string/pref_sync_category" />
<Preference
app:key="advanced"
app:fragment="io.github.wulkanowy.ui.modules.settings.advanced.AdvancedFragment"
app:icon="@drawable/ic_settings_advanced"
app:key="advanced"
app:summary="@string/pref_advanced_category_summary"
app:title="@string/pref_advanced_category"
app:fragment="io.github.wulkanowy.ui.modules.settings.advanced.AdvancedFragment" />
app:title="@string/pref_advanced_category" />
<Preference
app:key="about"
app:fragment="io.github.wulkanowy.ui.modules.about.AboutFragment"
app:icon="@drawable/ic_all_about"
app:key="about"
app:summary="@string/pref_about_category_summary"
app:title="@string/about_title"
app:fragment="io.github.wulkanowy.ui.modules.about.AboutFragment" />
app:title="@string/about_title" />
</PreferenceScreen>

View File

@ -0,0 +1,94 @@
package io.github.wulkanowy.ui.modules.settings.ads
import android.os.Bundle
import android.view.View
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.openInternetBrowser
import javax.inject.Inject
@AndroidEntryPoint
class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
@Inject
lateinit var presenter: AdsPresenter
override val titleStringId = R.string.pref_settings_ads_title
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.scheme_preferences_ads, rootKey)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.onAttachView(this)
}
override fun initView() {
findPreference<Preference>(getString(R.string.pref_key_ads_single_support))?.setOnPreferenceClickListener {
presenter.onWatchSingleAdSelected()
true
}
}
override fun showAd(ad: RewardedInterstitialAd) {
if (isVisible) {
ad.show(requireActivity()) {}
}
}
override fun showPrivacyPolicyDialog() {
MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.pref_ads_privacy_title))
.setMessage(getString(R.string.pref_ads_privacy_description))
.setPositiveButton(getString(R.string.pref_ads_privacy_agree)) { _, _ -> presenter.onAgreedPrivacy() }
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.setNeutralButton(getString(R.string.pref_ads_privacy_link)) { _, _ -> presenter.onPrivacySelected() }
.show()
}
override fun openPrivacyPolicy() {
requireContext().openInternetBrowser(
"https://wulkanowy.github.io/polityka-prywatnosci.html",
::showMessage
)
}
override fun showLoadingSupportAd(show: Boolean) {
findPreference<Preference>(getString(R.string.pref_key_ads_single_support))?.run {
isEnabled = !show
summary = if (show) getString(R.string.pref_ads_loading) else null
}
}
override fun showError(text: String, error: Throwable) {
(activity as? BaseActivity<*, *>)?.showError(text, error)
}
override fun showMessage(text: String) {
(activity as? BaseActivity<*, *>)?.showMessage(text)
}
override fun showExpiredDialog() {
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
}
override fun showChangePasswordSnackbar(redirectUrl: String) {
(activity as? BaseActivity<*, *>)?.showChangePasswordSnackbar(redirectUrl)
}
override fun openClearLoginView() {
(activity as? BaseActivity<*, *>)?.openClearLoginView()
}
override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
}

View File

@ -0,0 +1,41 @@
package io.github.wulkanowy.ui.modules.settings.ads
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.AdsHelper
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
class AdsPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val adsHelper: AdsHelper
) : BasePresenter<AdsView>(errorHandler, studentRepository) {
override fun onAttachView(view: AdsView) {
super.onAttachView(view)
view.initView()
Timber.i("Settings ads view was initialized")
}
fun onWatchSingleAdSelected() {
view?.showPrivacyPolicyDialog()
}
fun onPrivacySelected() {
view?.openPrivacyPolicy()
}
fun onAgreedPrivacy() {
view?.showLoadingSupportAd(true)
presenterScope.launch {
runCatching { adsHelper.getSupportAd() }
.onFailure(errorHandler::dispatch)
.onSuccess { it?.let { view?.showAd(it) } }
view?.showLoadingSupportAd(false)
}
}
}

View File

@ -0,0 +1,17 @@
package io.github.wulkanowy.ui.modules.settings.ads
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
import io.github.wulkanowy.ui.base.BaseView
interface AdsView : BaseView {
fun initView()
fun showAd(ad: RewardedInterstitialAd)
fun showPrivacyPolicyDialog()
fun openPrivacyPolicy()
fun showLoadingSupportAd(show: Boolean)
}

View File

@ -0,0 +1,39 @@
package io.github.wulkanowy.utils
import android.content.Context
import com.google.android.gms.ads.AdRequest
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.RewardedInterstitialAdLoadCallback
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.BuildConfig
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
class AdsHelper @Inject constructor(@ApplicationContext private val context: Context) {
suspend fun getSupportAd(): RewardedInterstitialAd? {
MobileAds.initialize(context)
val adRequest = AdRequest.Builder().build()
return suspendCoroutine {
RewardedInterstitialAd.load(
context,
BuildConfig.SINGLE_SUPPORT_AD_ID,
adRequest,
object : RewardedInterstitialAdLoadCallback() {
override fun onAdLoaded(rewardedInterstitialAd: RewardedInterstitialAd) {
it.resume(rewardedInterstitialAd)
}
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
it.resumeWithException(IllegalArgumentException(loadAdError.message))
}
})
}
}
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
app:fragment="io.github.wulkanowy.ui.modules.settings.appearance.AppearanceFragment"
app:icon="@drawable/ic_settings_appearance"
app:key="appearance"
app:summary="@string/pref_appearance_category_summary"
app:title="@string/pref_appearance_category" />
<Preference
app:fragment="io.github.wulkanowy.ui.modules.settings.notifications.NotificationsFragment"
app:icon="@drawable/ic_settings_notifications"
app:key="notifications"
app:summary="@string/pref_notifications_category_summary"
app:title="@string/pref_notifications_category" />
<Preference
app:fragment="io.github.wulkanowy.ui.modules.settings.sync.SyncFragment"
app:icon="@drawable/ic_settings_sync"
app:key="sync"
app:summary="@string/pref_sync_category_summary"
app:title="@string/pref_sync_category" />
<Preference
app:fragment="io.github.wulkanowy.ui.modules.settings.ads.AdsFragment"
app:icon="@drawable/ic_settings_ads"
app:key="ads"
app:summary="@string/pref_ads_category_summary"
app:title="@string/pref_settings_ads_title" />
<Preference
app:fragment="io.github.wulkanowy.ui.modules.settings.advanced.AdvancedFragment"
app:icon="@drawable/ic_settings_advanced"
app:key="advanced"
app:summary="@string/pref_advanced_category_summary"
app:title="@string/pref_advanced_category" />
<Preference
app:fragment="io.github.wulkanowy.ui.modules.about.AboutFragment"
app:icon="@drawable/ic_all_about"
app:key="about"
app:summary="@string/pref_about_category_summary"
app:title="@string/about_title" />
</PreferenceScreen>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_ads_support_category_name">
<Preference
app:iconSpaceReserved="false"
app:key="@string/pref_key_ads_single_support"
app:singleLineTitle="true"
app:title="@string/pref_ads_support" />
</PreferenceCategory>
</PreferenceScreen>