zhabby_shorts 0.0.2
zhabby_shorts: ^0.0.2 copied to clipboard
Shorts for Flutter.
Zhabby Shorts #
A high-performance Flutter plugin for TikTok-style short video feeds with HLS streaming support, adaptive video fitting, and thumbnail preview capabilities.
Features #
- 🎥 HLS Streaming: Full support for HTTP Live Streaming (HLS) with adaptive bitrate
- 📱 TikTok-style Feed: Vertical scrolling video feed optimized for mobile
- 🖼️ Thumbnail Support: Show custom thumbnails with fade animations while videos load
- 📐 Adaptive Video Fitting: Multiple fitting modes (contain, cover, fill) that adapt to video dimensions
- ⚡ Performance Optimized: Video preloading, texture pooling, and smooth transitions
- 🔄 Auto-loop: Seamless video looping capabilities
- 📊 Rich Callbacks: Detailed playback state tracking and debugging information
- 🎮 Gesture Support: Built-in tap handling and custom gesture support
- 🚀 Memory Efficient: Intelligent resource management and cleanup
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
zhabby_shorts: ^1.0.0
Then run:
flutter pub get
Quick Start #
1. Basic Setup #
import 'package:zhabby_shorts/zhabby_shorts.dart';
class VideoFeedScreen extends StatefulWidget {
@override
State<VideoFeedScreen> createState() => _VideoFeedScreenState();
}
class _VideoFeedScreenState extends State<VideoFeedScreen> {
late final ShortsPlayerController _player;
final List<String> _videoUrls = [
'https://example.com/video1.m3u8',
'https://example.com/video2.m3u8',
'https://example.com/video3.m3u8',
];
@override
void initState() {
super.initState();
_player = ShortsPlayerController();
_initializePlayer();
}
Future<void> _initializePlayer() async {
await _player.init();
await _player.appendUrls(0, _videoUrls);
await _player.setLooping(true);
// Prime first few videos for smooth playback
for (int i = 0; i < 3 && i < _videoUrls.length; i++) {
await _player.attach(i);
await _player.prime(i);
}
// Start playing first video
if (_videoUrls.isNotEmpty) {
await _player.switchTo(0);
}
}
@override
void dispose() {
_player.release();
super.dispose();
}
}
2. Using AdaptiveVideoFeedPlayer #
PageView.builder(
scrollDirection: Axis.vertical,
onPageChanged: (index) async {
await _player.switchTo(index);
},
itemCount: _videoUrls.length,
itemBuilder: (context, index) {
return AdaptiveVideoFeedPlayer(
index: index,
controller: _player,
isActive: _currentIndex == index,
fit: VideoFit.cover, // or VideoFit.contain, VideoFit.fill
showDebugInfo: false,
onTap: () {
// Handle tap events
},
);
},
)
3. Adding Thumbnails #
// Set video URLs with thumbnails
for (int i = 0; i < _videoUrls.length; i++) {
await _player.setUrl(i, _videoUrls[i],
thumbnailUrl: 'https://example.com/thumb$i.jpg');
}
// Or use AdaptiveVideoPlayer directly with thumbnail
AdaptiveVideoPlayer(
index: index,
controller: _player,
thumbnailUrl: 'https://example.com/thumbnail.jpg',
fit: VideoFit.cover,
showDebugInfo: true,
)
API Reference #
ShortsPlayerController #
The main controller class for managing video playback.
Core Methods
// Initialize the player
Future<void> init()
// Add video URLs to the player
Future<void> appendUrls(int startIndex, List<String> urls)
// Set video URL for a specific index (with optional thumbnail)
Future<void> setUrl(int index, String url, {String? thumbnailUrl})
// Switch to and play a specific video
Future<void> switchTo(int index)
// Attach texture for rendering
Future<int> attach(int index)
// Prime video for faster startup
Future<void> prime(int index)
// Playback control
Future<void> play()
Future<void> pause()
Future<void> togglePlayPause()
// Configuration
Future<void> setLooping(bool enabled)
Future<void> setVolume(double volume) // 0.0 to 1.0
Future<void> setMuted(bool enabled)
Future<void> setProgressTracking({bool enabled = true, int? intervalMs})
// Resource management
Future<void> release()
Future<void> disposeIndex(int index)
State Access
// Get video status for specific index
VideoStatus? getVideoStatus(int index)
// Get detailed player state
PlayerStateInfo? getPlayerState(int index)
// Get current active index
int? get activeIndex
// Get playback info
Map<String, dynamic>? get currentPlaybackInfo
AdaptiveVideoPlayer #
A widget that automatically adapts to video dimensions and aspect ratios.
AdaptiveVideoPlayer({
required int index,
required ShortsPlayerController controller,
VideoFit fit = VideoFit.contain,
Color backgroundColor = Colors.black,
Widget? loadingWidget,
Widget? errorWidget,
bool showDebugInfo = false,
String? thumbnailUrl,
Function(int index, double width, double height, double aspectRatio)? onDimensionsChanged,
Function(int index, String state)? onStateChanged,
})
AdaptiveVideoFeedPlayer #
Specialized widget for vertical feeds (like TikTok).
AdaptiveVideoFeedPlayer({
required int index,
required ShortsPlayerController controller,
required bool isActive,
VideoFit fit = VideoFit.cover,
bool showDebugInfo = false,
VoidCallback? onTap,
})
VideoFit Modes #
VideoFit.contain: Maintain aspect ratio, fit entirely within bounds (letterbox/pillarbox)VideoFit.cover: Maintain aspect ratio, fill bounds completely (crop if necessary)VideoFit.fill: Fill bounds exactly, may distort aspect ratio
Advanced Usage #
Performance Optimization #
// Prewarm adjacent videos for smooth scrolling
await _player.prewarm(next: nextIndex, prev: prevIndex);
// Configure video quality for adaptive streaming
await _player.setQuality(
peakBps: 2000000, // 2 Mbps
maxWidth: 1080,
maxHeight: 1920,
);
// Enable progress tracking with custom interval
await _player.setProgressTracking(
enabled: true,
intervalMs: 500, // Update every 500ms
);
Debug Information #
// Enable debug overlay
AdaptiveVideoPlayer(
showDebugInfo: true,
// ... other parameters
)
// Get detailed diagnostics
await _player.diagnoseVideoState(index);
// Listen to player state updates
_player.onPlayerStateInfoUpdate = (PlayerStateInfo stateInfo) {
print('Player ${stateInfo.index}: ${stateInfo.playerStatus}');
};
Custom Callbacks #
final methodChannel = _player.methodChannel;
methodChannel.onVideoLoaded = (int index, String url) {
print('Video $index loaded: $url');
};
methodChannel.onBufferingUpdate = (int index, String url, int percent) {
print('Video $index buffering: $percent%');
};
methodChannel.onError = (int index, String url, String errorMessage, String errorCode) {
print('Error in video $index: $errorMessage');
};
Example #
Check out the full example in the /example folder, which demonstrates:
- Vertical video feed with PageView
- Dynamic video fitting modes
- Comprehensive debug information
- Thumbnail support with fade animations
- Performance monitoring
- Error handling
Requirements #
- Flutter 2.5.0+
- Dart 2.14.0+
- iOS 11.0+
- Android API level 21+
Platform Support #
| Platform | Support |
|---|---|
| iOS | ✅ |
| Android | ✅ |
| Web | ❌ |
| Desktop | ❌ |
License #
This project is licensed under the MIT License - see the LICENSE file for details.