# Copilot Instructions for splash_video ## Project Overview A Flutter package for video splash screens using `media_kit`. Provides smooth transitions from native splash to video playback with overlay support and manual controls. ## Architecture ### Core Components - **`SplashVideo`** ([lib/widgets/splash_video_w.dart](../lib/widgets/splash_video_w.dart)) - Main widget orchestrating lifecycle, overlays, and navigation - **`SplashVideoPlayer`** ([lib/widgets/splash_video_player_w.dart](../lib/widgets/splash_video_player_w.dart)) - Internal widget handling media_kit Player/VideoController - **`SplashVideoController`** ([lib/splash_video_controller.dart](../lib/splash_video_controller.dart)) - Public API for play/pause/skip with underlying Player access - **`VideoConfig`** ([lib/video_config.dart](../lib/video_config.dart)) - Configuration: fitMode, volume, playImmediately, useSafeArea - **`Source`** (sealed class in [lib/video_source.dart](../lib/video_source.dart)) - Video sources: `AssetSource`, `NetworkSource`, `DeviceFileSource`, `BytesSource` ### Key Pattern: Deferred First Frame The package uses Flutter's `deferFirstFrame`/`allowFirstFrame` to prevent jank: ```dart // In main() - call SplashVideo.initialize() ONLY if first screen is SplashVideo SplashVideo.initialize(); // Defers frame + initializes MediaKit // Later, SplashVideo.resume() is called automatically when video loads ``` ### Widget Composition ``` SplashVideo (lifecycle, navigation, overlays) └── SplashVideoPlayer (media_kit integration) └── Video widget from media_kit_video ``` ## Development Commands ```bash # Run all unit tests flutter test # Run specific test flutter test test/video_source_test.dart # Run with coverage flutter test --coverage # Integration tests (from example/) cd example && flutter test integration_test/plugin_integration_test.dart # Run example app cd example && flutter run ``` ## Conventions ### Source Types (Sealed Class) Always use the appropriate `Source` subclass - the sealed class prevents external subclassing: ```dart AssetSource('assets/videos/splash.mp4') // Bundled assets NetworkSource('https://example.com/video.mp4') // URLs (validates format) DeviceFileSource('/path/to/video.mp4') // Local files BytesSource(Uint8List) // In-memory bytes ``` ### VideoFitMode Maps to Flutter's `BoxFit`. Default is `cover` for splash screens (fills screen, may crop). ### Controller Lifecycle - Controller must be disposed by the caller (not the widget) - Access `controller.player` only after widget is built (throws `StateError` otherwise) - For looping videos, controller is **required** ### Error Handling - Use `SplashVideoException` for package-specific errors - Provide `onVideoError` callback for graceful degradation - In debug mode, diagnostic prints prefixed with `SplashVideoPlayer:` or `SplashVideo:` ## Testing Patterns Tests use Arrange-Act-Assert pattern. Widget tests should handle async initialization: ```dart group('FeatureName', () { test('should do something', () { // Arrange - setup // Act - execute // Assert - verify with expect() }); }); ``` See [test/README.md](../test/README.md) for comprehensive testing guide. ## File Structure ``` lib/ ├── splash_video.dart # Library exports (barrel file) ├── splash_video_controller.dart ├── splash_video_enums.dart # VideoFitMode + BoxFit extension ├── video_config.dart ├── video_source.dart # Sealed Source class hierarchy ├── utils.dart # Typedefs, exceptions, extensions └── widgets/ ├── splash_video_w.dart # Main public widget └── splash_video_player_w.dart # Internal player widget ``` ## Platform Support All platforms via media_kit: Android, iOS, macOS, Windows, Linux. Platform-specific libs are in pubspec.yaml dependencies. ## Workflow Rules - **Documentation format**: Create all documentation with lowercase filenames and `.rst` format, no emojis - **End of task**: Always ask if tests and documentation should be updated (README.md is critical) - **No auto-docs**: Do not create a document for every feature/change - ask if comprehensive documentation is wanted at task end - **No silent removal**: Never remove functionality without explicit user confirmation