# splash_video

A Flutter package for creating smooth video splash screens using media_kit. Provides seamless transitions from native splash screens to video playback with flexible overlay support and manual controls.

## Platform Support

| Platform | Supported |
|----------|-----------|
| Android | ✅ |
| iOS | ✅ |
| macOS | ✅ |
| Windows | ✅ |
| Linux | ✅ |

## Features

- ✨ **Smooth Transitions** - Defer first frame pattern prevents jank between native and video splash
- 🎬 **Media Kit Integration** - Cross-platform video playback with hardware acceleration
- 🎮 **Manual Controls** - Full controller access for play, pause, skip operations
- 🔄 **Looping Support** - Infinite video loops with user-controlled exit
- 📱 **Flexible Overlays** - Title, footer, and custom overlay widgets
- 🎯 **Auto-Navigation** - Automatic screen transitions or manual control
- 🎨 **7 Scale Modes** - Cover, contain, fill, fitWidth, fitHeight, scaleDown, none
- 📐 **Aspect Ratio Control** - Full control over video sizing and scaling strategies

## Installation

Add to your `pubspec.yaml`:

```yaml
dependencies:
  splash_video: ^0.1.3

## Quick Start

### 1. Initialize in main()

```dart
import 'package:flutter/material.dart';
import 'package:media_kit/media_kit.dart';
import 'package:splash_video/splash_video.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Required: Initialize media_kit
  SplashVideo.initialize();
  
  runApp(MyApp());
}
```

### 2. Basic Usage (Auto-Navigate)

```dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SplashVideo(
        source: AssetSource('assets/videos/splash.mp4'),
        nextScreen: HomeScreen(),
        backgroundColor: Colors.black,
      ),
    );
  }
}
```

## Usage Examples

### Auto-Navigation

Video plays and automatically navigates to the next screen:

```dart
SplashVideo(
  source: AssetSource('assets/videos/splash.mp4'),
  nextScreen: HomeScreen(),
  backgroundColor: Colors.black,
)
```

### Manual Control

Use a callback for custom logic after video completes:

```dart
SplashVideo(
  source: AssetSource('assets/videos/splash.mp4'),
  onVideoComplete: () {
    // Custom logic
    // ...
    // ...
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(builder: (_) => HomeScreen()),
    );
  },
)
```

### Looping Video with Controller

Create an infinite loop that the user can manually exit:

```dart
class MyScreen extends StatefulWidget {
  @override
  State<MyScreen> createState() => _MyScreenState();
}

class _MyScreenState extends State<MyScreen> {
  late final SplashVideoController controller;

  @override
  void initState() {
    super.initState();
    controller = SplashVideoController(loopVideo: true);
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  void _onSkip() {
    controller.skip();
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(builder: (_) => HomeScreen()),
    );
  }

  @override
  Widget build(BuildContext context) {
    return SplashVideo(
      source: AssetSource('assets/videos/splash.mp4'),
      controller: controller,
      footerWidget: ElevatedButton(
        onPressed: _onSkip,
        child: Text('Skip'),
      ),
    );
  }
}
```

### With Overlays

Add title, footer, and custom overlays:

```dart
SplashVideo(
  source: AssetSource('assets/videos/splash.mp4'),
  nextScreen: HomeScreen(),
  backgroundColor: Colors.black,
  
  // Title at top
  titleWidget: Padding(
    padding: EdgeInsets.all(20),
    child: Text(
      'Welcome',
      style: TextStyle(fontSize: 32, color: Colors.white),
    ),
  ),
  
  // Footer at bottom
  footerWidget: CircularProgressIndicator(),
  
  // Custom overlay with full control
  overlayBuilder: (context) => Positioned(
    right: 20,
    top: 100,
    child: Text('v1.0.0', style: TextStyle(color: Colors.white)),
  ),
)
```

### Network Video

Load video from URL:

```dart
SplashVideo(
  source: NetworkFileSource('https://example.com/splash.mp4'),
  nextScreen: HomeScreen(),
)
```

### Video Scale Modes

Control how your video fills the screen with 7 different scale modes:

```dart
SplashVideo(
  source: AssetSource('assets/videos/splash.mp4'),
  nextScreen: HomeScreen(),
  videoConfig: VideoConfig(
    fitMode: VideoFitMode.cover, // Fill screen, may crop edges (best for splash)
  ),
)
```

**Available Scale Modes:**

- `VideoFitMode.cover` - Fill screen, maintain aspect, may crop (recommended for splash screens)
- `VideoFitMode.contain` - Fit inside, maintain aspect, may show letterboxing
- `VideoFitMode.fill` - Stretch to fill (ignores aspect ratio, may distort)
- `VideoFitMode.fitWidth` - Match width, maintain aspect
- `VideoFitMode.fitHeight` - Match height, maintain aspect
- `VideoFitMode.scaleDown` - Like contain but won't upscale beyond original size
- `VideoFitMode.none` - Original size, centered

**Quick Comparison:**

| Fit Mode | Best For | Maintains Aspect | May Crop | May Letterbox |
|----------|----------|------------------|----------|---------------|
| `cover` | Splash screens, hero sections | ✅ | ✅ | ❌ |
| `contain` | Viewing entire video | ✅ | ❌ | ✅ |
| `fill` | Exact fill (rare) | ❌ | ❌ | ❌ |
| `fitWidth` | Horizontal content | ✅ | Vertical | Horizontal |
| `fitHeight` | Vertical content | ✅ | Horizontal | Vertical |
| `scaleDown` | Small videos | ✅ | ❌ | ✅ |
| `none` | Pixel-perfect display | ✅ | ❌ | ✅ |

### Custom Configuration

```dart
SplashVideo(
  source: AssetSource('assets/videos/splash.mp4'),
  nextScreen: HomeScreen(),
  videoConfig: VideoConfig(
    playImmediately: true,
    fitMode: VideoFitMode.cover,
    useSafeArea: true,
    volume: 50.0,
    enableAudio: true,
    onPlayerInitialized: (player) {
      print('Player ready: ${player.state.duration}');
    },
  ),
)
```

## API Reference

### SplashVideo

Main widget for video splash screen.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `source` | `Source` | ✅ | Video source (Asset, Network, DeviceFile, Bytes) |
| `controller` | `SplashVideoController?` | ⚠️ | Required when looping is enabled |
| `videoConfig` | `VideoConfig?` | ❌ | Playback configuration |
| `backgroundColor` | `Color?` | ❌ | Background color behind video |
| `titleWidget` | `Widget?` | ❌ | Widget at top of screen |
| `footerWidget` | `Widget?` | ❌ | Widget at bottom of screen |
| `overlayBuilder` | `Widget Function(BuildContext)?` | ❌ | Custom overlay builder |
| `nextScreen` | `Widget?` | ❌ | Screen to navigate to (auto-navigate) |
| `onVideoComplete` | `VoidCallback?` | ❌ | Callback when video completes (manual control) |
| `onSourceLoaded` | `VoidCallback?` | ❌ | Callback when video loads |

**Validation Rules:**
- Cannot use both `nextScreen` and `onVideoComplete`
- Looping videos require `controller` and cannot use `nextScreen` or `onVideoComplete`

### SplashVideoController

Controls video playback.

```dart
final controller = SplashVideoController(loopVideo: true);

// Access media_kit Player
controller.player.play();
controller.player.pause();
controller.player.seek(Duration(seconds: 5));

// Controller methods
controller.play();
controller.pause();
controller.skip(); // Complete immediately
controller.dispose();
```

### VideoConfig

Configuration for video playback.

```dart
VideoConfig(
  playImmediately: true,            // Auto-play on load
  fitMode: VideoFitMode.cover,      // How video fills screen (7 modes)
  useSafeArea: false,               // Wrap in SafeArea
  volume: 80.0,                     // Volume (0-100), default 80
  enableAudio: true,                // Enable/disable audio track
  onPlayerInitialized: (player) { },// Player ready callback
)
```

**Parameters:**
- `playImmediately` (bool) - Start playing immediately after load. Default: `true`
- `fitMode` (VideoFitMode) - Video sizing strategy. Default: `VideoFitMode.cover`
- `useSafeArea` (bool) - Avoid notches and system UI. Default: `false`
- `volume` (double) - Initial volume 0-100. Default: `80.0`
- `enableAudio` (bool) - Enable audio track (more efficient than volume=0). Default: `true`
- `onPlayerInitialized` (Function?) - Callback when Player is ready

### Source Types

```dart
// Asset bundled with app
AssetSource('assets/videos/splash.mp4')

// Network URL
NetworkFileSource('https://example.com/video.mp4')

// Device file
DeviceFileSource('/path/to/video.mp4')

// Raw bytes
BytesSource(videoBytes)
```

## Migration Guide

### From v0.0.1 to v0.0.2+

The `VideoAspectRatio` enum has been replaced with `VideoFitMode` for better video sizing control:

**Old API (Deprecated but still works):**
```dart
VideoConfig(
  videoVisibilityEnum: VideoAspectRatio.useFullScreen,
)
```

**New API (Recommended):**
```dart
VideoConfig(
  fitMode: VideoFitMode.cover,
)
```

**Migration Table:**

| Old API | New API | Notes |
|---------|---------|-------|
| `VideoAspectRatio.useFullScreen` | `VideoFitMode.cover` | Now properly fills screen |
| `VideoAspectRatio.useAspectRatio` | `VideoFitMode.contain` | Same behavior |
| `VideoAspectRatio.none` | `VideoFitMode.none` | Same behavior |
| `videoVisibilityEnum` parameter | `fitMode` parameter | Renamed for clarity |

The old API will be removed in v1.0.0. Update your code to use the new `fitMode` parameter.

## Lifecycle Methods

```dart
// Defer first frame (prevents jank)
SplashVideo.initialize();

// Resumes frame painting
SplashVideo(
  source: AssetSource(Assets.splashVideo),
  backgroundColor: Colors.black,
  onVideoComplete: () => _videoComplete(),
  videoConfig: const VideoConfig(
    scale: VideoScaleMode.fill,
    useSafeArea: true,
  )
);
```

## License

MIT License - see LICENSE file for details.

