Version casi lista
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
#if canImport(GoogleMobileAds)
|
||||
import GoogleMobileAds
|
||||
|
||||
struct AdBannerView: View {
|
||||
var adUnitId: String = AdMobConfig.resolvedBannerHomeUnitId
|
||||
@State private var state: BannerState = .loading
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Rectangle()
|
||||
.fill(Color.mealMoodTextSecondary.opacity(0.22))
|
||||
.frame(height: 1)
|
||||
|
||||
ZStack {
|
||||
Color.mealMoodSurface
|
||||
|
||||
BannerBridge(adUnitId: adUnitId, state: $state)
|
||||
|
||||
if state != .loaded {
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "megaphone")
|
||||
Text(state == .loading ? "ads_loading" : "ads_unavailable")
|
||||
.font(.mealMoodCaption)
|
||||
}
|
||||
.foregroundColor(.mealMoodTextSecondary)
|
||||
}
|
||||
}
|
||||
.frame(height: 56)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.mealMoodSurface)
|
||||
}
|
||||
}
|
||||
|
||||
private enum BannerState {
|
||||
case loading
|
||||
case loaded
|
||||
case failed
|
||||
}
|
||||
|
||||
private struct BannerBridge: UIViewRepresentable {
|
||||
let adUnitId: String
|
||||
@Binding var state: BannerState
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(state: $state)
|
||||
}
|
||||
|
||||
func makeUIView(context: Context) -> UIView {
|
||||
let container = UIView()
|
||||
container.backgroundColor = UIColor(Color.mealMoodSurface)
|
||||
|
||||
let width = max(UIScreen.main.bounds.width, 320)
|
||||
let adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(width)
|
||||
let banner = GADBannerView(adSize: adSize)
|
||||
banner.adUnitID = adUnitId
|
||||
banner.delegate = context.coordinator
|
||||
banner.rootViewController = rootViewController()
|
||||
banner.translatesAutoresizingMaskIntoConstraints = false
|
||||
banner.backgroundColor = .clear
|
||||
context.coordinator.bannerView = banner
|
||||
|
||||
container.addSubview(banner)
|
||||
NSLayoutConstraint.activate([
|
||||
banner.centerXAnchor.constraint(equalTo: container.centerXAnchor),
|
||||
banner.centerYAnchor.constraint(equalTo: container.centerYAnchor),
|
||||
banner.widthAnchor.constraint(equalToConstant: adSize.size.width),
|
||||
banner.heightAnchor.constraint(equalToConstant: adSize.size.height)
|
||||
])
|
||||
|
||||
context.coordinator.loadBannerIfPossible()
|
||||
return container
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIView, context: Context) {
|
||||
context.coordinator.bannerView?.rootViewController = rootViewController()
|
||||
context.coordinator.loadBannerIfPossible()
|
||||
}
|
||||
|
||||
private func rootViewController() -> UIViewController? {
|
||||
UIApplication.shared.connectedScenes
|
||||
.compactMap { $0 as? UIWindowScene }
|
||||
.flatMap(\.windows)
|
||||
.first(where: \.isKeyWindow)?
|
||||
.rootViewController
|
||||
}
|
||||
|
||||
final class Coordinator: NSObject, GADBannerViewDelegate {
|
||||
@Binding var state: BannerState
|
||||
weak var bannerView: GADBannerView?
|
||||
private var didRequestLoad = false
|
||||
private var retryCount = 0
|
||||
|
||||
init(state: Binding<BannerState>) {
|
||||
self._state = state
|
||||
}
|
||||
|
||||
func loadBannerIfPossible() {
|
||||
guard let bannerView, bannerView.rootViewController != nil else { return }
|
||||
guard !didRequestLoad else { return }
|
||||
didRequestLoad = true
|
||||
state = .loading
|
||||
bannerView.load(GADRequest())
|
||||
}
|
||||
|
||||
func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
|
||||
state = .loaded
|
||||
retryCount = 0
|
||||
}
|
||||
|
||||
func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: any Error) {
|
||||
state = .failed
|
||||
didRequestLoad = false
|
||||
|
||||
if retryCount < 2 {
|
||||
retryCount += 1
|
||||
loadBannerIfPossible()
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
print("AdMob banner failed (\(retryCount)): \(error.localizedDescription)")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct AdBannerView: View {
|
||||
var adUnitId: String = AdMobConfig.resolvedBannerHomeUnitId
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Rectangle()
|
||||
.fill(Color.mealMoodTextSecondary.opacity(0.22))
|
||||
.frame(height: 1)
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "megaphone")
|
||||
Text("ads_unavailable")
|
||||
.font(.mealMoodCaption)
|
||||
}
|
||||
.foregroundColor(.mealMoodTextSecondary)
|
||||
.frame(maxWidth: .infinity, minHeight: 56)
|
||||
.background(Color.mealMoodSurface)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.mealMoodSurface)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user