wistia_enforce 1.0.0
wistia_enforce: ^1.0.0 copied to clipboard
A Flutter video player for Wistia that enforces watch time. Features include progress tracking, resume functionality, and callbacks for saving user progress.
import 'package:flutter/material.dart';
import 'package:wistia_enforce/wistia_enforce.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Wistia Enforce Player Example',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const VideoScreen(),
);
}
}
class VideoScreen extends StatefulWidget {
const VideoScreen({super.key});
@override
State<VideoScreen> createState() => _VideoScreenState();
}
class _VideoScreenState extends State<VideoScreen> {
// State variables to hold the information from the player callbacks.
int _remainingTime = 0;
bool _isEnforcementMet = false;
String _errorMessage = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Wistia Player Example'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// --- Wistia Player ---
// This is the main widget from the package.
// Be sure to replace 'your_wistia_media_id' with a real one.
WistiaEnforcePlayer(
mediaId: 'your_wistia_media_id', // TODO: Replace with your Wistia media ID
stopSeeking: true,
requiredWatchTime: 120, // Require 2 minutes of watch time
previouslyWatchedTime: 30, // Start with 30 seconds of progress
progressUpdateInterval: 10, // Save progress every 10 seconds
onProgress: (remainingTime, isEnforcementMet) {
// This callback fires frequently. Use it to update the UI.
setState(() {
_remainingTime = remainingTime;
_isEnforcementMet = isEnforcementMet;
_errorMessage = ''; // Clear previous errors on progress
});
},
onProgressUpdate: (secondsWatched) async {
// This callback fires every `progressUpdateInterval` seconds of *new* watch time.
// It's the perfect place to save progress to your backend.
print('New progress: $secondsWatched seconds. Saving to backend...');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Saved $secondsWatched seconds of progress!'),
duration: const Duration(seconds: 2),
),
);
// Example of a network call:
// await ApiService.saveVideoProgress(userId: 123, seconds: secondsWatched);
},
onEnforcementTimeReached: () {
// This fires only once when the required watch time is met.
print('Enforcement time reached!');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Congratulations! You have completed the video.'),
backgroundColor: Colors.green,
),
);
},
onError: (error) {
// Handle any errors from the player (e.g., failed to load video).
setState(() {
_errorMessage = error;
});
print('Player Error: $error');
},
),
const SizedBox(height: 24),
// --- Status Display ---
// UI to show the current state of the player.
const Text(
'Player Status',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
if (_errorMessage.isNotEmpty)
Text(
'Error: $_errorMessage',
style: const TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
)
else ...[
Text('Required watch time met: $_isEnforcementMet'),
Text('Remaining time to watch: $_remainingTime seconds'),
],
const SizedBox(height: 24),
ElevatedButton(
onPressed: _isEnforcementMet ? () {
// Only allow proceeding if the enforcement is met.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Moving to the next lesson!')),
);
} : null, // Button is disabled until enforcement is met.
child: const Text('Go to Next Lesson'),
),
],
),
),
);
}
}