velocity_ads 0.1.0
velocity_ads: ^0.1.0 copied to clipboard
A Flutter plugin for VelocityAds SDK - AI-powered contextual advertising for Android.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:velocity_ads/velocity_ads.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'VelocityAds Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const ExampleHomePage(),
);
}
}
class ExampleHomePage extends StatefulWidget {
const ExampleHomePage({super.key});
@override
State<ExampleHomePage> createState() => _ExampleHomePageState();
}
class _ExampleHomePageState extends State<ExampleHomePage> {
bool _isInitialized = false;
bool _isLoading = false;
NativeAd? _currentAd;
String? _errorMessage;
final TextEditingController _promptController = TextEditingController(
text: 'Best running shoes for marathon training',
);
@override
void initState() {
super.initState();
_initializeSDK();
}
@override
void dispose() {
_promptController.dispose();
super.dispose();
}
Future<void> _initializeSDK() async {
try {
setState(() {
_isLoading = true;
_errorMessage = null;
});
final result = await VelocityAds.initialize(
appKey: 'demo-app-key',
);
setState(() {
_isInitialized = result['success'] == true;
_isLoading = false;
});
if (_isInitialized) {
_showSnackBar('SDK initialized successfully', Colors.green);
}
} catch (e) {
setState(() {
_isLoading = false;
_errorMessage = 'Initialization failed: $e';
});
_showSnackBar('Failed to initialize: $e', Colors.red);
}
}
Future<void> _loadAd() async {
if (!_isInitialized) {
_showSnackBar('Please initialize SDK first', Colors.orange);
return;
}
try {
setState(() {
_isLoading = true;
_errorMessage = null;
_currentAd = null;
});
final ad = await VelocityAds.loadNativeAd(
prompt: _promptController.text,
aiResponse: 'Here are some great options for marathon training shoes...',
dimensions: const AdDimensions(width: 320, height: 250),
);
setState(() {
_currentAd = ad;
_isLoading = false;
});
_showSnackBar('Ad loaded successfully', Colors.green);
} catch (e) {
setState(() {
_isLoading = false;
_errorMessage = 'Failed to load ad: $e';
});
_showSnackBar('Failed to load ad: $e', Colors.red);
}
}
Future<void> _loadAdWithConversation() async {
if (!_isInitialized) {
_showSnackBar('Please initialize SDK first', Colors.orange);
return;
}
try {
setState(() {
_isLoading = true;
_errorMessage = null;
_currentAd = null;
});
final conversationHistory = [
ConversationMessage.user('I want to start running'),
ConversationMessage.assistant(
'Great! Running is an excellent exercise. Are you looking for beginner tips?',
),
ConversationMessage.user('Yes, and I need good running shoes'),
ConversationMessage.assistant(
'For running shoes, I recommend looking for proper cushioning and support...',
),
];
final ad = await VelocityAds.loadNativeAd(
prompt: _promptController.text,
aiResponse: 'Here are some excellent running shoes for marathon training...',
conversationHistory: conversationHistory,
dimensions: const AdDimensions(width: 320, height: 250),
);
setState(() {
_currentAd = ad;
_isLoading = false;
});
_showSnackBar('Ad loaded with conversation context', Colors.green);
} catch (e) {
setState(() {
_isLoading = false;
_errorMessage = 'Failed to load ad: $e';
});
_showSnackBar('Failed to load ad: $e', Colors.red);
}
}
void _setGDPRConsent(bool consent) {
VelocityAds.setConsent(consent);
_showSnackBar(
'GDPR consent ${consent ? "granted" : "denied"}',
Colors.blue,
);
}
void _setCCPADoNotSell(bool doNotSell) {
VelocityAds.setDoNotSell(doNotSell);
_showSnackBar(
'CCPA Do Not Sell: ${doNotSell ? "enabled" : "disabled"}',
Colors.blue,
);
}
void _showSnackBar(String message, Color backgroundColor) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: backgroundColor,
duration: const Duration(seconds: 2),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('VelocityAds Example'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Status Section
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'SDK Status',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Row(
children: [
Icon(
_isInitialized ? Icons.check_circle : Icons.cancel,
color: _isInitialized ? Colors.green : Colors.red,
),
const SizedBox(width: 8),
Text(
_isInitialized ? 'Initialized' : 'Not Initialized',
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
],
),
),
),
const SizedBox(height: 16),
// Load Ad Section
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Load Ad',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
TextField(
controller: _promptController,
decoration: const InputDecoration(
labelText: 'Ad Prompt',
border: OutlineInputBorder(),
hintText: 'Enter search query or user intent',
),
maxLines: 2,
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _isLoading ? null : _loadAd,
icon: const Icon(Icons.download),
label: const Text('Load Ad'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
onPressed:
_isLoading ? null : _loadAdWithConversation,
icon: const Icon(Icons.chat),
label: const Text('With Context'),
),
),
],
),
],
),
),
),
const SizedBox(height: 16),
// Privacy Controls
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Privacy Controls',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
ListTile(
title: const Text('Grant GDPR Consent'),
leading: const Icon(Icons.privacy_tip),
onTap: () => _setGDPRConsent(true),
),
ListTile(
title: const Text('Deny GDPR Consent'),
leading: const Icon(Icons.block),
onTap: () => _setGDPRConsent(false),
),
const Divider(),
ListTile(
title: const Text('Enable CCPA Do Not Sell'),
leading: const Icon(Icons.shield),
onTap: () => _setCCPADoNotSell(true),
),
ListTile(
title: const Text('Disable CCPA Do Not Sell'),
leading: const Icon(Icons.shield_outlined),
onTap: () => _setCCPADoNotSell(false),
),
],
),
),
),
const SizedBox(height: 16),
// Loading Indicator
if (_isLoading)
const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: CircularProgressIndicator(),
),
),
// Error Message
if (_errorMessage != null)
Card(
color: Colors.red.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
const Icon(Icons.error, color: Colors.red),
const SizedBox(width: 8),
Expanded(
child: Text(
_errorMessage!,
style: const TextStyle(color: Colors.red),
),
),
],
),
),
),
// Ad Display
if (_currentAd != null) _buildAdDisplay(_currentAd!),
],
),
),
);
}
Widget _buildAdDisplay(NativeAd ad) {
return Card(
elevation: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header
Container(
padding: const EdgeInsets.all(16.0),
color: Theme.of(context).colorScheme.primaryContainer,
child: Row(
children: [
const Icon(Icons.ad_units),
const SizedBox(width: 8),
Text(
'Native Ad',
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
Text(
'Sponsored',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
// Ad Content
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title
Text(
ad.title,
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
// Description
Text(
ad.description,
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 12),
// Image (if available)
if (ad.imageUrl.isNotEmpty)
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
ad.imageUrl,
height: 200,
width: double.infinity,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
height: 200,
color: Colors.grey.shade200,
child: const Center(
child: Icon(Icons.image_not_supported),
),
);
},
),
),
const SizedBox(height: 12),
// Additional Info
Wrap(
spacing: 8,
runSpacing: 8,
children: [
if (ad.rating != null)
Chip(
avatar: const Icon(Icons.star, size: 16),
label: Text('${ad.rating}/5'),
),
if (ad.price != null)
Chip(
avatar: const Icon(Icons.attach_money, size: 16),
label: Text(ad.price!),
),
if (ad.category.isNotEmpty)
Chip(
label: Text(ad.category),
),
],
),
const SizedBox(height: 12),
// CTA Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
_showSnackBar(
'Ad clicked: ${ad.clickUrl}',
Colors.blue,
);
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
),
child: Text(ad.callToAction),
),
),
// Sponsored By
const SizedBox(height: 8),
Text(
'By ${ad.sponsoredBy}',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
],
),
);
}
}