Skip to content

Commit 90d4462

Browse files
authored
Merge pull request #297 from naz013/release/9.6.0
Merge release/9.6.0 into master
2 parents 9b34a9e + 894bb57 commit 90d4462

File tree

308 files changed

+4163
-18983
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

308 files changed

+4163
-18983
lines changed

.github/workflows/build_and_test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- 'master'
7+
- 'develop'
78
- 'feature/**'
89
- 'release/**'
910

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ android {
2222
applicationId = "com.cray.software.justreminder"
2323
minSdk = libs.versions.minSdk.get().toInt()
2424
targetSdk = libs.versions.targetSdk.get().toInt()
25-
versionCode = 328
26-
versionName = "9.5.2"
25+
versionCode = 329
26+
versionName = "9.6.0"
2727
multiDexEnabled = true
2828
renderscriptTargetApi = 23
2929
renderscriptSupportModeEnabled = true

app/src/free/java/com/elementary/tasks/AdsProvider.kt

Lines changed: 16 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,18 @@ package com.elementary.tasks
22

33
import android.app.Activity
44
import android.content.Context
5-
import android.view.LayoutInflater
65
import android.view.ViewGroup
7-
import android.widget.Button
8-
import android.widget.ImageView
9-
import android.widget.RatingBar
10-
import android.widget.TextView
116
import androidx.annotation.LayoutRes
127
import com.elementary.tasks.core.utils.SuperUtil
138
import com.github.naz013.logging.Logger
14-
import com.github.naz013.ui.common.view.gone
15-
import com.github.naz013.ui.common.view.transparent
16-
import com.github.naz013.ui.common.view.visible
17-
import com.google.android.gms.ads.AdListener
18-
import com.google.android.gms.ads.AdLoader
19-
import com.google.android.gms.ads.AdRequest
20-
import com.google.android.gms.ads.AdSize
21-
import com.google.android.gms.ads.AdView
22-
import com.google.android.gms.ads.LoadAdError
239
import com.google.android.gms.ads.MobileAds
24-
import com.google.android.gms.ads.nativead.NativeAd
25-
import com.google.android.gms.ads.nativead.NativeAdOptions
26-
import com.google.android.gms.ads.nativead.NativeAdView
2710
import com.google.android.ump.ConsentForm
2811
import com.google.android.ump.ConsentInformation
2912
import com.google.android.ump.ConsentRequestParameters
3013
import com.google.android.ump.UserMessagingPlatform
3114

3215
class AdsProvider {
3316

34-
private var nativeAdd: NativeAd? = null
3517
private var consentInformation: ConsentInformation? = null
3618
private var consentForm: ConsentForm? = null
3719

@@ -83,26 +65,15 @@ class AdsProvider {
8365
bannerId: String,
8466
failListener: (() -> Unit)? = null
8567
) {
86-
val adView = AdView(viewGroup.context)
87-
adView.setAdSize(AdSize.LARGE_BANNER)
88-
adView.adUnitId = bannerId
89-
90-
viewGroup.removeAllViews()
91-
viewGroup.addView(adView)
92-
93-
val adRequest = AdRequest.Builder().build()
94-
adView.loadAd(adRequest)
95-
96-
adView.adListener = object : AdListener() {
97-
override fun onAdFailedToLoad(adError: LoadAdError) {
98-
adView.gone()
99-
failListener?.invoke()
100-
}
101-
102-
override fun onAdLoaded() {
103-
adView.visible()
68+
RotatingBannerAdsProvider(
69+
bannerId = bannerId,
70+
viewGroup = viewGroup,
71+
onAdsFailureCallback = object : OnAdsFailureCallback {
72+
override fun onAdsFailure() {
73+
failListener?.invoke()
74+
}
10475
}
105-
}
76+
)
10677
}
10778

10879
fun showNativeBanner(
@@ -111,104 +82,20 @@ class AdsProvider {
11182
@LayoutRes res: Int,
11283
failListener: (() -> Unit)? = null
11384
) {
114-
val adLoader = AdLoader.Builder(viewGroup.context, bannerId)
115-
.forNativeAd { ad: NativeAd ->
116-
nativeAdd?.destroy()
117-
nativeAdd = ad
118-
val adView = LayoutInflater.from(viewGroup.context).inflate(res, null) as NativeAdView
119-
populateUnifiedNativeAdView(ad, adView)
120-
viewGroup.removeAllViews()
121-
viewGroup.addView(adView)
122-
}
123-
.withAdListener(object : AdListener() {
124-
override fun onAdFailedToLoad(error: LoadAdError) {
125-
super.onAdFailedToLoad(error)
126-
Logger.e("Failed to load native ad: ${error.message}")
85+
RotatingNativeAdsProvider(
86+
viewGroup = viewGroup,
87+
bannerId = bannerId,
88+
res = res,
89+
onAdsFailureCallback = object : OnAdsFailureCallback {
90+
override fun onAdsFailure() {
12791
wasError = true
12892
failListener?.invoke()
12993
}
130-
})
131-
.withNativeAdOptions(
132-
NativeAdOptions.Builder()
133-
.setRequestMultipleImages(false)
134-
.build()
135-
)
136-
.build()
137-
adLoader.loadAd(AdRequest.Builder().build())
138-
}
139-
140-
fun destroy() {
141-
nativeAdd?.destroy()
142-
}
143-
144-
private fun populateUnifiedNativeAdView(nativeAd: NativeAd, adView: NativeAdView) {
145-
adView.mediaView = adView.findViewById(R.id.ad_media)
146-
147-
adView.headlineView = adView.findViewById(R.id.ad_headline)
148-
adView.bodyView = adView.findViewById(R.id.ad_body)
149-
adView.callToActionView = adView.findViewById(R.id.ad_call_to_action)
150-
adView.iconView = adView.findViewById(R.id.ad_app_icon)
151-
adView.priceView = adView.findViewById(R.id.ad_price)
152-
adView.starRatingView = adView.findViewById(R.id.ad_stars)
153-
adView.storeView = adView.findViewById(R.id.ad_store)
154-
adView.advertiserView = adView.findViewById(R.id.ad_advertiser)
155-
156-
(adView.headlineView as TextView).text = nativeAd.headline
157-
if (nativeAd.body == null) {
158-
adView.bodyView?.transparent()
159-
} else {
160-
adView.bodyView?.visible()
161-
(adView.bodyView as TextView).text = nativeAd.body
162-
}
163-
164-
if (nativeAd.callToAction == null) {
165-
adView.callToActionView?.transparent()
166-
} else {
167-
adView.callToActionView?.visible()
168-
(adView.callToActionView as Button).text = nativeAd.callToAction
169-
}
170-
171-
if (nativeAd.icon == null) {
172-
adView.iconView?.gone()
173-
} else {
174-
(adView.iconView as ImageView).setImageDrawable(
175-
nativeAd.icon?.drawable
176-
)
177-
adView.iconView?.visible()
178-
}
179-
180-
if (nativeAd.price == null) {
181-
adView.priceView?.transparent()
182-
} else {
183-
adView.priceView?.visible()
184-
(adView.priceView as TextView).text = nativeAd.price
185-
}
186-
187-
if (nativeAd.store == null) {
188-
adView.storeView?.transparent()
189-
} else {
190-
adView.storeView?.visible()
191-
(adView.storeView as TextView).text = nativeAd.store
192-
}
193-
194-
if (nativeAd.starRating == null) {
195-
adView.starRatingView?.transparent()
196-
} else {
197-
(adView.starRatingView as RatingBar).rating = nativeAd.starRating!!.toFloat()
198-
adView.starRatingView?.visible()
199-
}
200-
201-
if (nativeAd.advertiser == null) {
202-
adView.advertiserView?.transparent()
203-
} else {
204-
(adView.advertiserView as TextView).text = nativeAd.advertiser
205-
adView.advertiserView?.visible()
206-
}
207-
adView.setNativeAd(nativeAd)
94+
}
95+
)
20896
}
20997

21098
companion object {
211-
private const val ADMOB_ID = "ca-app-pub-5133908997831400~9675541050"
21299
const val REMINDER_PREVIEW_BANNER_ID = "ca-app-pub-5133908997831400/1084030852"
213100
const val NOTE_PREVIEW_BANNER_ID = "ca-app-pub-5133908997831400/4831704177"
214101
const val BIRTHDAY_PREVIEW_BANNER_ID = "ca-app-pub-5133908997831400/1262280397"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.elementary.tasks
2+
3+
interface OnAdsFailureCallback {
4+
fun onAdsFailure()
5+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.elementary.tasks
2+
3+
import android.os.Handler
4+
import android.os.Looper
5+
import android.view.ViewGroup
6+
import androidx.core.view.doOnDetach
7+
import com.github.naz013.logging.Logger
8+
import com.github.naz013.ui.common.view.gone
9+
import com.github.naz013.ui.common.view.visible
10+
import com.google.android.gms.ads.AdListener
11+
import com.google.android.gms.ads.AdRequest
12+
import com.google.android.gms.ads.AdSize
13+
import com.google.android.gms.ads.AdView
14+
import com.google.android.gms.ads.LoadAdError
15+
import java.lang.ref.WeakReference
16+
17+
class RotatingBannerAdsProvider(
18+
private val bannerId: String,
19+
viewGroup: ViewGroup,
20+
onAdsFailureCallback: OnAdsFailureCallback
21+
) {
22+
23+
private val parent = WeakReference(viewGroup)
24+
private val callback = WeakReference(onAdsFailureCallback)
25+
26+
private val handler = Handler(Looper.getMainLooper())
27+
private val runnable = Runnable { scheduleAds() }
28+
29+
init {
30+
scheduleAds()
31+
listenParent()
32+
}
33+
34+
private fun listenParent() {
35+
parent.get()?.doOnDetach {
36+
Logger.d(TAG, "Parent view is detached, will not show ADS")
37+
handler.removeCallbacks(runnable)
38+
callback.clear()
39+
parent.clear()
40+
}
41+
}
42+
43+
private fun scheduleAds() {
44+
if (safeLoadAds()) {
45+
Logger.d(TAG, "Scheduled ads")
46+
handler.postDelayed(runnable, ADS_DURATION)
47+
}
48+
}
49+
50+
private fun safeLoadAds(): Boolean {
51+
return runCatching { loadAds() }.getOrNull() ?: false
52+
}
53+
54+
private fun loadAds(): Boolean {
55+
val viewGroup = parent.get() ?: return false.also {
56+
Logger.e(TAG, "Will not show ADS, Parent view is null")
57+
}
58+
val adView = AdView(viewGroup.context)
59+
adView.setAdSize(AdSize.LARGE_BANNER)
60+
adView.adUnitId = bannerId
61+
62+
viewGroup.removeAllViews()
63+
viewGroup.addView(adView)
64+
65+
val adRequest = AdRequest.Builder().build()
66+
adView.loadAd(adRequest)
67+
68+
adView.adListener = object : AdListener() {
69+
override fun onAdFailedToLoad(adError: LoadAdError) {
70+
adView.gone()
71+
callback.get()?.onAdsFailure()
72+
}
73+
74+
override fun onAdLoaded() {
75+
adView.visible()
76+
}
77+
}
78+
return true
79+
}
80+
81+
companion object {
82+
private const val TAG = "RotatingBannerAdsProvider"
83+
private const val ADS_DURATION = 1 * 60 * 1000L // 1 minute
84+
}
85+
}

0 commit comments

Comments
 (0)