Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

81 feat allow ads to be hidden until fully loaded (android) #113

Merged
merged 3 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,11 @@ scripts:
concurrency: 1
packageFilters:
scope: 'xandr_example'

run:example:fadeOnDone:
run: fvm flutter run -t lib/main_fadeOnDone.dart
description: Run the example app fading in once ad loaded.
exec:
concurrency: 1
packageFilters:
scope: 'xandr_example'
123 changes: 123 additions & 0 deletions packages/xandr/example/lib/main_fadeOnDone.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:xandr/ad_banner.dart';
import 'package:xandr/ad_size.dart';
import 'package:xandr/load_mode.dart';
import 'package:xandr/xandr.dart';

void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const XandrExample(),
);
}
}

class XandrExample extends StatefulWidget {
const XandrExample({super.key});

@override
State<XandrExample> createState() => _XandrExampleState();
}

class _XandrExampleState extends State<XandrExample> {
late final XandrController _controller;
final ScrollController _scrollController = ScrollController();
final StreamController<ScrollPosition> _checkIfAdIsInViewport =
StreamController();

@override
void dispose() {
_scrollController.dispose();
_checkIfAdIsInViewport.close();
super.dispose();
}

@override
void initState() {
super.initState();

_controller = XandrController()..init(9517);
_scrollController.addListener(() {
_checkIfAdIsInViewport.add(_scrollController.position);
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('xandr sample - banner'),
),
body: Center(
child: SingleChildScrollView(
controller: _scrollController,
child: Column(
children: [
const Text('Lorem Ipsum is simply dummy text of the printing and '
'typesetting industry. Lorem Ipsum has been the boo '
'standard dummy text ever since the 1500s, when an aha '
'printer took a galley of type and scrambled it to m'),
FadeAd(
adBanner: AdBanner(
controller: _controller,
//placementID: '17058950',
inventoryCode: 'bunte_webdesktop_home_homepage_hor_1',
adSizes: const [AdSize(728, 90)], //[AdSize(300, 250)],
customKeywords: const {
'kw': ['test-kw', 'demoads'],
},
resizeAdToFitContainer: true,
//enableLazyLoad: true,
),
),
const Text('Lorem Ipsum is simply dummy text of the printing and '
'typesetting industry. Lorem Ipsum has been the boo '
'standard dummy text ever since the 1500s, when an aha '
'printer took a galley of type and scrambled it to v'),
const Text('Lorem Ipsum is simply dummy text of the printing and '
'typesetting industry. Lorem Ipsum has been the boo '
'standard dummy text ever since the 1500s, when an aha '
'printer took a galley of type and scrambled it to v'),
],
),
),
),
);
}
}

class FadeAd extends StatelessWidget {
const FadeAd({required this.adBanner, super.key});
final AdBanner adBanner;

@override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: adBanner.doneLoading.future,
builder: (ctx, snapshot) {
return AnimatedContainer(
duration: const Duration(milliseconds: 3000),
height: snapshot.hasData && snapshot.data! ? 100 : 1,
width: double.infinity,
child: adBanner,
);
},
);
}
}
36 changes: 31 additions & 5 deletions packages/xandr/lib/ad_banner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class AdBanner extends StatefulWidget {
LoadMode? loadMode,
double? width,
double? height,
this.onBannerFinishLoading,
}) : assert(adSizes.isNotEmpty, 'adSizes must not be empty'),
assert(
placementID != null || inventoryCode != null,
Expand Down Expand Up @@ -106,6 +107,11 @@ class AdBanner extends StatefulWidget {
/// The controller for managing multi ad requests.
final MultiAdRequestController? multiAdRequestController;

final _DoneLoadingCallback? onBannerFinishLoading;

/// A completer that indicates when loading is done.
final Completer<bool> doneLoading = Completer();

@override
State<AdBanner> createState() => _AdBannerState();
}
Expand All @@ -127,8 +133,6 @@ class _AdBannerState extends State<AdBanner> {
_checkViewport((widget.loadMode as WhenInViewport).pixelOffset);
});
}
_height = widget.height;
_width = widget.width;
super.initState();
}

Expand Down Expand Up @@ -164,17 +168,34 @@ class _AdBannerState extends State<AdBanner> {
}

void changeSize(double width, double height) {
debugPrint('>>>> changeSize: $width x $height');
setState(() {
_width = width;
_height = height;
});
}

void onDoneLoading({required bool success}) {
void onDoneLoading({required bool success, int? width, int? height}) {
if (widget.onBannerFinishLoading != null) {
widget.onBannerFinishLoading!(
success: success,
width: width,
height: height,
);
}

debugPrint('>>>> onDoneLoading: $success');
setState(() {
_loading = false;
_loaded = success;
});
if (!widget.doneLoading.isCompleted) {
widget.doneLoading.complete(success);
}

if (success && width != null && height != null) {
changeSize(width.toDouble(), height.toDouble());
}
}

Future<bool> waitIsInitialized() async {
Expand Down Expand Up @@ -228,6 +249,9 @@ class _AdBannerState extends State<AdBanner> {
return const Text('Error initializing Xandr, error: false');
}
} else if (snapshot.hasError) {
if (!widget.doneLoading.isCompleted) {
widget.doneLoading.completeError(snapshot.error!);
}
return const Text('unknown Error initializing Xandr');
} else {
return SizedBox(
Expand Down Expand Up @@ -267,7 +291,8 @@ enum ClickThroughAction {
}
}

typedef _DoneLoadingCallback = void Function({required bool success});
typedef _DoneLoadingCallback = void Function(
{required bool success, int? width, int? height});

class _HostAdBannerView extends StatelessWidget {
_HostAdBannerView({
Expand Down Expand Up @@ -365,8 +390,9 @@ class _HostAdBannerView extends StatelessWidget {
widgetId.complete(id);
}
controller.listen(id, (event) {
debugPrint('>>>> controller listen: $event');
if (event is BannerAdLoadedEvent) {
_onDoneLoading(success: true);
_onDoneLoading(success: true, width: event.width, height: event.height);
delegate?.onBannerAdLoaded?.call(event);
} else if (event is BannerAdLoadedErrorEvent) {
_onDoneLoading(success: false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ open class XandrAdListener(private var widgetId: Int, private var flutterApi: Xa
"Xandr.BannerView",
">>> Ad Request failed, AdView:p0=$p0 ResultCode:p1=$p1"
)

flutterApi.onAdLoadedError(
widgetId.toLong(),
"Error while loading banner ad: ${p1?.message}"
) { }
}

override fun onAdExpanded(p0: AdView?) {
Expand Down
Loading