bmdrm_mobile 0.0.21
bmdrm_mobile: ^0.0.21 copied to clipboard
A Flutter plugin for DRM-protected video playback with watermark support.
example/lib/main.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:bmdrm_mobile/bmdrm_video_player.dart';
import 'package:bmdrm_mobile/bmdrm_resume_store.dart';
const String _sessionJson =
'{"edge":"https://YOUR_EDGE_SERVER.video-crypt.com","videoId":"YOUR_VIDEO_ID","signature":"YOUR_SIGNATURE","userId":"YOUR_USER_ID","subscriptionId":"YOUR_SUBSCRIPTION_ID","sessionId":"YOUR_SESSION_ID","nonce":"YOUR_NONCE","date":0}';
class Lesson {
const Lesson(this.id, this.title);
final String id;
final String title;
}
// Each lesson tracks its own resume position under its id.
const _lessons = [
Lesson('lesson-1', 'Lesson 1 · DRM playback'),
Lesson('lesson-2', 'Lesson 2 · Adaptive streaming'),
];
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
final scheme = ColorScheme.fromSeed(seedColor: Colors.indigo);
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'BMDRM Player',
theme: ThemeData(useMaterial3: true, colorScheme: scheme),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<ResumeEntry> _inProgress = const [];
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
final entries = await VideoPlayerController.continueWatching();
if (mounted) setState(() => _inProgress = entries);
}
Future<void> _open(Lesson lesson) async {
await Navigator.of(
context,
).push(MaterialPageRoute(builder: (_) => PlayerPage(lesson: lesson)));
_load();
}
String _titleFor(String id) =>
_lessons.firstWhere((l) => l.id == id, orElse: () => Lesson(id, id)).title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('BMDRM Player')),
body: ListView(
children: [
if (_inProgress.isNotEmpty) ...[
const _SectionTitle('Continue watching'),
for (final e in _inProgress)
ListTile(
leading: const Icon(Icons.play_circle_fill),
title: Text(_titleFor(e.resumeId)),
subtitle: LinearProgressIndicator(value: e.progress),
trailing: Text('${(e.progress * 100).round()}%'),
onTap: () => _open(Lesson(e.resumeId, _titleFor(e.resumeId))),
),
const Divider(height: 24),
],
const _SectionTitle('Lessons'),
for (final lesson in _lessons)
ListTile(
leading: const Icon(Icons.ondemand_video),
title: Text(lesson.title),
onTap: () => _open(lesson),
),
],
),
);
}
}
class _SectionTitle extends StatelessWidget {
const _SectionTitle(this.text);
final String text;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Text(text, style: Theme.of(context).textTheme.titleMedium),
);
}
}
class PlayerPage extends StatelessWidget {
const PlayerPage({super.key, required this.lesson});
final Lesson lesson;
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final videoHeight = (size.width * 9 / 16)
.clamp(0.0, size.height * 0.7)
.toDouble();
return Scaffold(
appBar: AppBar(title: Text(lesson.title)),
body: SingleChildScrollView(
child: Column(
children: [
BmdrmVideoPlayer.drmFromBackendSession(
backendSession: jsonDecode(_sessionJson),
width: double.infinity,
height: videoHeight,
autoPlay: true,
resumeId: lesson.id,
resumeFromLastPosition: true,
fullscreenDrawerBuilder: (context, controller) =>
_AboutDrawer(onClose: controller.closeDrawer),
fullscreenDrawerToggle: const BmdrmDrawerToggle(
label: 'À propos de cette leçon',
),
),
],
),
),
);
}
}
/// Example content for the player's fullscreen drawer. Any Flutter widget works
/// here — the plugin only provides the sliding panel and the toggle button.
class _AboutDrawer extends StatelessWidget {
const _AboutDrawer({required this.onClose});
final VoidCallback onClose;
@override
Widget build(BuildContext context) {
return SafeArea(
left: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 8, 4),
child: Row(
children: [
const Expanded(
child: Text(
'About this lesson',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700),
),
),
IconButton(icon: const Icon(Icons.close), onPressed: onClose),
],
),
),
const Expanded(
child: Padding(
padding: EdgeInsets.all(16),
child: Text(
'Your custom fullscreen panel goes here — put any Flutter '
'widgets you like beside the video.',
),
),
),
],
),
);
}
}