396 lines
9.8 KiB
ReStructuredText
396 lines
9.8 KiB
ReStructuredText
====================================
|
|
Splash Video Implementation Plan
|
|
====================================
|
|
|
|
:Date: January 24, 2026
|
|
:Version: 0.0.1
|
|
:Author: Development Team
|
|
|
|
Overview
|
|
========
|
|
|
|
This document outlines the implementation plan for the ``splash_video`` Flutter package, a video splash screen library using ``media_kit`` for video playback. The design follows patterns from ``splash_master`` but focuses exclusively on video playback functionality.
|
|
|
|
Design Principles
|
|
=================
|
|
|
|
1. **Single Responsibility**: Only video splash functionality (no Lottie, Rive, or CLI tools)
|
|
2. **Media Kit Integration**: Use ``media_kit`` + ``video_player_media_kit`` for cross-platform video playback
|
|
3. **Defer First Frame Pattern**: Smooth transition from native splash to video splash
|
|
4. **Manual Control**: Provide controller for advanced use cases
|
|
5. **Flexible Overlays**: Support custom UI elements over video
|
|
|
|
Architecture
|
|
============
|
|
|
|
Two-Widget Pattern
|
|
------------------
|
|
|
|
The package uses a two-widget architecture:
|
|
|
|
1. **SplashVideo**: Main public widget handling lifecycle, navigation, and timing
|
|
2. **VideoSplash**: Internal widget focused on video playback using media_kit
|
|
|
|
Core Components
|
|
===============
|
|
|
|
1. SplashVideoController
|
|
------------------------
|
|
|
|
**Purpose**: Provides control over video playback and configuration
|
|
|
|
**Properties**:
|
|
|
|
- ``loopVideo: bool`` - Enable infinite looping
|
|
- ``player: Player`` - Access to media_kit Player instance
|
|
|
|
**Methods**:
|
|
|
|
- ``play()`` - Start video playback
|
|
- ``pause()`` - Pause video playback
|
|
- ``skip()`` - Complete video immediately and trigger navigation
|
|
- ``dispose()`` - Clean up resources
|
|
|
|
**Configuration Rules**:
|
|
|
|
- If ``loopVideo == true``: Controller is **required**
|
|
- Looping videos cannot use ``onVideoComplete`` or ``nextScreen``
|
|
|
|
2. SplashVideo Widget
|
|
---------------------
|
|
|
|
**Purpose**: Main entry point for video splash functionality
|
|
|
|
**Parameters**:
|
|
|
|
Required:
|
|
- ``source: Source`` - Video source (Asset, Network, DeviceFile, Bytes)
|
|
|
|
Optional Configuration:
|
|
- ``controller: SplashVideoController?`` - Required if looping
|
|
- ``videoConfig: VideoConfig?`` - Playback configuration
|
|
- ``backgroundColor: Color?`` - Background color behind video
|
|
|
|
Overlay Widgets:
|
|
- ``titleWidget: Widget?`` - Widget positioned at top
|
|
- ``footerWidget: Widget?`` - Widget positioned at bottom
|
|
- ``overlayBuilder: Widget Function(BuildContext)?`` - Custom overlay with full control
|
|
|
|
Navigation/Completion:
|
|
- ``nextScreen: Widget?`` - Auto-navigate on completion
|
|
- ``onVideoComplete: VoidCallback?`` - Manual control callback (priority over nextScreen)
|
|
|
|
Lifecycle:
|
|
- ``onSourceLoaded: VoidCallback?`` - Called when video loads (defaults to resume())
|
|
|
|
3. VideoConfig Class
|
|
--------------------
|
|
|
|
**Purpose**: Configuration options for video playback
|
|
|
|
**Properties**:
|
|
|
|
- ``playImmediately: bool`` (default: true) - Auto-play on load
|
|
- ``videoVisibilityEnum: VisibilityEnum`` (default: useFullScreen) - Display mode
|
|
- ``useSafeArea: bool`` (default: false) - Wrap in SafeArea
|
|
- ``volume: double`` (default: 100.0) - Initial volume (0.0-100.0)
|
|
- ``onPlayerInitialized: Function(Player)?`` - Callback with Player access
|
|
|
|
**Note**: ``loopVideo`` removed (now in controller)
|
|
|
|
4. Source Types
|
|
---------------
|
|
|
|
Sealed class hierarchy for video sources:
|
|
|
|
- ``AssetSource(String path)`` - Bundled asset
|
|
- ``NetworkFileSource(String path)`` - Remote URL
|
|
- ``DeviceFileSource(String path)`` - Local file system
|
|
- ``BytesSource(Uint8List bytes)`` - In-memory bytes
|
|
|
|
5. VisibilityEnum
|
|
-----------------
|
|
|
|
Controls video display behavior:
|
|
|
|
- ``useFullScreen`` - Fill entire screen
|
|
- ``useAspectRatio`` - Maintain video aspect ratio
|
|
- ``none`` - No special sizing
|
|
|
|
Validation Rules
|
|
================
|
|
|
|
The widget enforces these rules at runtime:
|
|
|
|
Looping Videos
|
|
--------------
|
|
|
|
When ``controller.loopVideo == true``:
|
|
|
|
- ✅ Controller MUST be provided
|
|
- ❌ Cannot set ``onVideoComplete``
|
|
- ❌ Cannot set ``nextScreen``
|
|
- ✅ User must call ``controller.skip()`` to end
|
|
|
|
Non-Looping Videos
|
|
------------------
|
|
|
|
When not looping:
|
|
|
|
- ✅ Can set ``nextScreen`` (auto-navigate)
|
|
- ✅ Can set ``onVideoComplete`` (manual control)
|
|
- ❌ Cannot set BOTH ``nextScreen`` AND ``onVideoComplete`` (throws error)
|
|
|
|
Overlay Rendering Order
|
|
========================
|
|
|
|
Stack layers (bottom to top):
|
|
|
|
1. **Video** - Base layer
|
|
2. **titleWidget** - Positioned at top of screen
|
|
3. **footerWidget** - Positioned at bottom of screen
|
|
4. **overlayBuilder** - Full custom overlay (rendered last)
|
|
|
|
All overlays are optional and can be combined.
|
|
|
|
Lifecycle Flow
|
|
==============
|
|
|
|
Initialization Flow
|
|
-------------------
|
|
|
|
1. ``SplashVideo.initialize()`` called in ``main()``
|
|
- Defers Flutter's first frame
|
|
- Native splash remains visible
|
|
|
|
2. ``SplashVideo`` widget mounts
|
|
- Creates/receives controller
|
|
- Validates configuration
|
|
- Initializes ``VideoSplash``
|
|
|
|
3. Video loads
|
|
- ``onSourceLoaded`` callback fires
|
|
- Defaults to ``SplashVideo.resume()``
|
|
- Flutter frames begin rendering
|
|
- Smooth transition from native to video
|
|
|
|
4. Video plays
|
|
- Overlays render on top
|
|
- User can interact via controller
|
|
|
|
Completion Flow (Non-Looping)
|
|
------------------------------
|
|
|
|
1. Video reaches end
|
|
2. Check for completion handlers:
|
|
- If ``onVideoComplete`` set → call it
|
|
- Else if ``nextScreen`` set → auto-navigate
|
|
- Else → do nothing
|
|
|
|
Completion Flow (Looping)
|
|
--------------------------
|
|
|
|
1. Video loops infinitely
|
|
2. User must call ``controller.skip()`` or ``controller.pause()``
|
|
3. No automatic completion
|
|
|
|
Implementation Checklist
|
|
=========================
|
|
|
|
Phase 1: Core Implementation
|
|
-----------------------------
|
|
|
|
1. ✅ Create ``SplashVideoController`` class
|
|
2. ✅ Update ``VideoConfig`` (remove loopVideo)
|
|
3. ✅ Update ``VideoSplash`` widget for media_kit integration
|
|
4. ✅ Create main ``SplashVideo`` widget with:
|
|
- Validation logic
|
|
- Overlay support
|
|
- Navigation handling
|
|
- Lifecycle management
|
|
5. ✅ Update ``lib/splash_video.dart`` exports
|
|
6. ✅ Create example application
|
|
7. ✅ Update README.md with usage examples
|
|
|
|
Phase 2: Future Enhancements
|
|
-----------------------------
|
|
|
|
- 🔜 Boomerang loop support
|
|
- 🔜 Additional overlay positioning options
|
|
- 🔜 Advanced playback controls
|
|
- 🔜 Analytics/telemetry hooks
|
|
|
|
Example Usage
|
|
=============
|
|
|
|
Non-Looping with Auto-Navigation
|
|
---------------------------------
|
|
|
|
.. code-block:: dart
|
|
|
|
void main() {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
SplashVideo.initialize();
|
|
runApp(MyApp());
|
|
}
|
|
|
|
class MyApp extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
home: SplashVideo(
|
|
source: AssetSource('assets/videos/splash.mp4'),
|
|
nextScreen: HomeScreen(),
|
|
backgroundColor: Colors.black,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
Looping with Manual Control
|
|
----------------------------
|
|
|
|
.. code-block:: dart
|
|
|
|
class MyApp extends StatefulWidget {
|
|
@override
|
|
State<MyApp> createState() => _MyAppState();
|
|
}
|
|
|
|
class _MyAppState extends State<MyApp> {
|
|
late SplashVideoController controller;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
controller = SplashVideoController(loopVideo: true);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
home: SplashVideo(
|
|
source: AssetSource('assets/videos/splash.mp4'),
|
|
controller: controller,
|
|
titleWidget: Text(
|
|
'Welcome',
|
|
style: TextStyle(fontSize: 32, color: Colors.white),
|
|
),
|
|
footerWidget: ElevatedButton(
|
|
onPressed: () => controller.skip(),
|
|
child: Text('Skip'),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
Manual Completion Control
|
|
--------------------------
|
|
|
|
.. code-block:: dart
|
|
|
|
SplashVideo(
|
|
source: AssetSource('assets/videos/splash.mp4'),
|
|
onVideoComplete: () {
|
|
// Custom logic
|
|
Navigator.pushReplacement(
|
|
context,
|
|
MaterialPageRoute(builder: (_) => HomeScreen()),
|
|
);
|
|
},
|
|
titleWidget: Text('Loading...'),
|
|
)
|
|
|
|
Custom Overlay
|
|
--------------
|
|
|
|
.. code-block:: dart
|
|
|
|
SplashVideo(
|
|
source: NetworkFileSource('https://example.com/splash.mp4'),
|
|
overlayBuilder: (context) => Stack(
|
|
children: [
|
|
Positioned(
|
|
top: 50,
|
|
left: 0,
|
|
right: 0,
|
|
child: Center(child: Text('Custom UI')),
|
|
),
|
|
Positioned(
|
|
bottom: 20,
|
|
right: 20,
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
|
|
Dependencies
|
|
============
|
|
|
|
Required packages in ``pubspec.yaml``:
|
|
|
|
.. code-block:: yaml
|
|
|
|
dependencies:
|
|
flutter:
|
|
sdk: flutter
|
|
media_kit: ^1.2.6
|
|
media_kit_video: ^2.0.1
|
|
video_player_media_kit: ^2.0.0
|
|
|
|
# Platform-specific libs
|
|
media_kit_libs_android_video: any
|
|
media_kit_libs_ios_video: any
|
|
media_kit_libs_macos_video: any
|
|
media_kit_libs_windows_video: any
|
|
media_kit_libs_linux: any
|
|
|
|
Testing Strategy
|
|
================
|
|
|
|
Unit Tests
|
|
----------
|
|
|
|
- Source type validation
|
|
- Controller state management
|
|
- Configuration validation
|
|
- Overlay composition
|
|
|
|
Widget Tests
|
|
------------
|
|
|
|
- Video playback initialization
|
|
- Navigation behavior
|
|
- Overlay rendering
|
|
- Lifecycle management
|
|
|
|
Integration Tests
|
|
-----------------
|
|
|
|
- End-to-end splash flow
|
|
- Platform-specific video playback
|
|
- Performance benchmarks
|
|
|
|
Notes
|
|
=====
|
|
|
|
- All file and class names follow lowercase conventions
|
|
- Follows Flutter/Dart style guide
|
|
- Media kit requires initialization in main()
|
|
- Defer pattern prevents frame jank during transition
|
|
- Controller pattern provides maximum flexibility
|
|
|
|
Document Status
|
|
===============
|
|
|
|
:Status: Approved for Implementation
|
|
:Next Review: After Phase 1 completion
|