Files
xtremflow/INTEGRATION_GUIDE.md
GitHub Copilot 91eb1ce5a0 Add download and subtitle services, enhance UI with continue watching and quality selector widgets
- Implemented DownloadService for managing download tasks, including start, pause, resume, and cancel functionalities.
- Created SubtitleService for handling subtitle tracks, parsing SRT and WebVTT formats, and downloading subtitles.
- Added ContinueWatchingWidget to display user's watch history with progress indicators.
- Developed QualitySelectorWidget for selecting video quality during playback, including auto quality adjustment.
- Introduced TrendingWidget and RecentlyAddedWidget to showcase trending and recently added content.
2026-03-26 10:34:18 +01:00

15 KiB

/// INTEGRATION GUIDE - XtremFlow Optimizations /// /// This guide shows how to integrate and use all the new optimization features

// ============================================ // 1. ADAPTIVE BITRATE STREAMING // ============================================

// In your player_screen.dart, use this: /* import 'package:xtremflow/core/services/adaptive_bitrate_service.dart';

class PlayerScreen extends ConsumerStatefulWidget { @override ConsumerState createState() => _PlayerScreenState(); }

class _PlayerScreenState extends ConsumerState { late QualitySelector _qualitySelector;

@override void initState() { super.initState(); _qualitySelector = QualitySelector( initialQuality: QualityProfiles.hd720p, ); }

@override Widget build(BuildContext context) { final currentQuality = _qualitySelector.currentQuality;

return Stack(
  children: [
    // Your video player widget
    VideoPlayer(url: _getStreamUrl(currentQuality)),
    
    // Quality indicator
    QualityIndicator(
      qualitySelector: _qualitySelector,
      onTap: () {
        showDialog(
          context: context,
          builder: (context) => QualitySelectorWidget(
            qualitySelector: _qualitySelector,
            onClose: () => Navigator.pop(context),
          ),
        );
      },
    ),
  ],
);

}

String getStreamUrl(QualityLevel quality) { // Return URL based on selected quality // Example: https://stream.example.com/video${quality.width}x${quality.height}.m3u8 return ''; } } */

// ============================================ // 2. SUBTITLES SUPPORT // ============================================

// Import and use: /* import 'package:xtremflow/features/iptv/services/subtitle_service.dart';

// Parse SRT file final srtContent = await rootBundle.loadString('subtitles/movie.srt'); final subtitleEntries = SubtitleService.parseSrt(srtContent);

// Get subtitle at specific time final currentSubtitle = SubtitleService.getSubtitleAtTime( subtitleEntries, Duration(seconds: currentPosition), );

// Download from URL final content = await SubtitleService.downloadSubtitle( 'https://example.com/subtitles.srt', ); final entries = SubtitleService.parseSrt(content);

// Display in player SubtitleOverlay( subtitle: currentSubtitle, position: Offset(0, size.height * 0.85), ) */

// ============================================ // 3. RECOMMEND SYSTEM (CONTINUE WATCHING, TRENDING) // ============================================

// In your dashboard_screen.dart: /* import 'package:xtremflow/features/iptv/providers/recommendations_provider.dart'; import 'package:xtremflow/features/iptv/widgets/continue_watching_widget.dart';

class DashboardScreen extends ConsumerStatefulWidget { @override ConsumerState createState() => _DashboardScreenState(); }

class _DashboardScreenState extends ConsumerState { @override Widget build(BuildContext context) { final watchHistory = ref.watch(watchHistoryProvider); final trending = ref.watch(trendingProvider);

return ListView(
  children: [
    // Continue Watching Section
    ContinueWatchingWidget(
      playlist: widget.playlist,
      content: widget.content,
      onItemTap: () {
        // Navigate to player
      },
    ),

    // Trending Section
    TrendingWidget(
      playlist: widget.playlist,
      content: widget.content,
      onItemTap: () {
        // Navigate to player
      },
    ),

    // Recently Added Section
    RecentlyAddedWidget(
      playlist: widget.playlist,
      content: widget.content,
      onItemTap: () {
        // Navigate to player
      },
    ),
  ],
);

} }

// Track watch position: void _onVideoProgress(Duration position, Duration duration) { final percentage = (position.inSeconds / duration.inSeconds) * 100; ref.read(watchHistoryProvider.notifier) .updateWatchTime(streamId, percentage); }

// Track trending: void _onVideoStart() { ref.read(trendingProvider.notifier).incrementViewCount(streamId); } */

// ============================================ // 4. OFFLINE DOWNLOADS // ============================================

// Download a video: /* import 'package:xtremflow/features/iptv/services/download_service.dart';

final downloadService = ref.read(downloadServiceProvider);

// Start download final task = await downloadService.startDownload( id: 'movie_12345', title: 'Awesome Movie', url: 'https://stream.example.com/movie.mp4', );

// Monitor progress _downloadUpdateTimer = Timer.periodic(Duration(milliseconds: 200), (timer) { final progress = downloadService.getDownloadProgress('movie_12345'); setState(() => _downloadProgress = progress); });

// Pause/Resume downloadService.pauseDownload('movie_12345'); downloadService.resumeDownload('movie_12345');

// Check if available offline if (downloadService.isAvailableOffline('movie_12345')) { final filePath = downloadService.getOfflineFilePath('movie_12345'); // Play from file path } */

// ============================================ // 5. NETWORK OPTIMIZATION & PROXY // ============================================

// Configure network with proxy: /* import 'package:xtremflow/core/services/network_service.dart';

final networkConfig = NetworkConfig( proxyUrl: 'http://proxy.example.com:8080', userAgent: 'CustomUser-Agent/1.0', customHeaders: { 'Authorization': 'Bearer token123', 'X-Custom-Header': 'value', }, connectTimeout: Duration(seconds: 30), receiveTimeout: Duration(seconds: 60), );

final networkService = OptimizedNetworkService(config: networkConfig);

// Update proxy at runtime ref.read(networkConfigProvider.notifier) .setProxy('http://new-proxy:8080'); */

// ============================================ // 6. CACHE MANAGEMENT // ============================================

// Use cache service: /* import 'package:xtremflow/core/services/cache_service.dart';

final cacheService = ref.read(cacheServiceProvider);

// Cache data with automatic size management cacheService.cache('channel_list_key', jsonEncodedList, estimatedSize: 50000);

// Retrieve cached data final cachedList = cacheService.get('channel_list_key');

// Check if valid if (cacheService.has('channel_list_key')) { // Use cached value }

// Get cache statistics final stats = cacheService.getStats(); print('Cache size: ${stats['totalSizeMb']}MB'); print('Items: ${stats['itemCount']}');

// Clear expired entries cacheService.clearExpired();

// Clear all cache cacheService.clear(); */

// ============================================ // 7. STREAMING METRICS & OPTIMIZATION // ============================================

// Monitor streaming quality: /* import 'package:xtremflow/core/services/streaming_optimizer.dart';

final optimizer = ref.watch(streamingOptimizerProvider);

Text('Quality: ${optimizer.quality.label}'), Text('Buffer: ${optimizer.bufferDurationMs}ms'), Text('Rebuffers: ${optimizer.rebufferCount}'),

// Record segment download ref.read(streamingOptimizerProvider.notifier) .recordSegmentDownload(bytesDownloaded, downloadDuration);

// Handle rebuffer ref.read(streamingOptimizerProvider.notifier) .rebufferDetected(Duration(milliseconds: 2000));

// View metrics history final history = ref.read(streamingOptimizerProvider.notifier) .getHistory(); */

// ============================================ // 8. EPG GRID VIEW // ============================================

// Navigate to EPG: /* import 'package:xtremflow/features/iptv/screens/epg_grid_screen.dart';

// In your navigation: context.push('/epg', extra: widget.playlist);

// Or open as bottom sheet showModalBottomSheet( context: context, builder: (context) => EpgGridScreen(playlist: widget.playlist), ); */

// ============================================ // 9. OPTIMIZATION CONFIG // ============================================

// Print optimization summary: /* import 'package:xtremflow/core/config/optimization_config.dart';

// On app startup OptimizationConfig.printSummary();

// Calibrate for device RuntimeOptimizations.calibrateForDevice( totalMemoryMb: 8000, freeMemoryMb: 2000, storageFreeMb: 50000, );

// Get dynamic cache sizes based on device final cacheSizeMb = RuntimeOptimizations.getDynamicCacheSize(); final imageCacheMb = RuntimeOptimizations.getDynamicImageCacheSize();

// Check device capabilities if (RuntimeOptimizations.hasHighPerformanceDevice) { // Enable all features } else if (RuntimeOptimizations.isLowMemoryMode) { // Disable heavy features } */

// ============================================ // 10. COMPLETE PLAYER INTEGRATION // ============================================

// Full player screen with all optimizations: /* import 'package:xtremflow/core/services/adaptive_bitrate_service.dart'; import 'package:xtremflow/core/services/streaming_optimizer.dart'; import 'package:xtremflow/features/iptv/services/subtitle_service.dart';

class OptimizedPlayerScreen extends ConsumerStatefulWidget { final String streamUrl; final int streamId;

const OptimizedPlayerScreen({ required this.streamUrl, required this.streamId, });

@override ConsumerState createState() => _OptimizedPlayerScreenState(); }

class _OptimizedPlayerScreenState extends ConsumerState { late QualitySelector _qualitySelector; late VideoPlayerController _controller; List _subtitles = []; String? _currentSubtitle;

@override void initState() { super.initState(); _initializePlayer(); }

void _initializePlayer() { // Setup quality selector _qualitySelector = QualitySelector( initialQuality: QualityProfiles.hd720p, );

// Initialize video player with adaptive quality URL
_controller = VideoPlayerController.network(
  _getQualityUrl(_qualitySelector.currentQuality),
);

// Load subtitles
_loadSubtitles();

// Start listening to playback events
_controller.addListener(_onPlayerStateChanged);

}

void _loadSubtitles() async { // Try to auto-download subtitles // Example: from OpenSubtitles API }

void _onPlayerStateChanged() { final position = _controller.value.position;

// Track watch progress
if (_controller.value.duration.inMilliseconds > 0) {
  final percentage = (position.inMilliseconds / 
      _controller.value.duration.inMilliseconds) * 100;
  ref.read(watchHistoryProvider.notifier)
      .updateWatchTime(widget.streamId, percentage);
}

// Update subtitle
if (_subtitles.isNotEmpty) {
  _currentSubtitle = SubtitleService.getSubtitleAtTime(
    _subtitles,
    position,
  );
  setState(() {});
}

// Record streaming metrics
final bytesEstimate = 1000; // Calculate from actual download
ref.read(streamingOptimizerProvider.notifier)
    .recordSegmentDownload(bytesEstimate, Duration(milliseconds: 500));

}

String getQualityUrl(QualityLevel quality) { // Return HLS master playlist or variant playlist return '${widget.streamUrl}/variant${quality.width}x${quality.height}.m3u8'; }

@override Widget build(BuildContext context) { final metrics = ref.watch(streamingOptimizerProvider);

return Stack(
  children: [
    // Video player
    AspectRatio(
      aspectRatio: _controller.value.aspectRatio,
      child: VideoPlayer(_controller),
    ),

    // Subtitles overlay
    if (_currentSubtitle != null)
      Positioned(
        bottom: 60,
        left: 0,
        right: 0,
        child: Center(
          child: Container(
            padding: EdgeInsets.all(8),
            decoration: BoxDecoration(
              color: Colors.black54,
              borderRadius: BorderRadius.circular(4),
            ),
            child: Text(
              _currentSubtitle!,
              textAlign: TextAlign.center,
              style: TextStyle(
                color: Colors.white,
                fontSize: 14,
              ),
            ),
          ),
        ),
      ),

    // Quality indicator + metrics
    Positioned(
      top: 16,
      right: 16,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          QualityIndicator(
            qualitySelector: _qualitySelector,
            onTap: () {
              showDialog(
                context: context,
                builder: (context) => QualitySelectorWidget(
                  qualitySelector: _qualitySelector,
                  onClose: () => Navigator.pop(context),
                ),
              );
            },
          ),
          SizedBox(height: 8),
          BandwidthMonitor(qualitySelector: _qualitySelector),
        ],
      ),
    ),

    // Metrics display (debug)
    if (kDebugMode)
      Positioned(
        bottom: 16,
        left: 16,
        child: Container(
          padding: EdgeInsets.all(8),
          decoration: BoxDecoration(
            color: Colors.black54,
            borderRadius: BorderRadius.circular(4),
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Rebuffers: ${metrics.rebufferCount}',
                style: TextStyle(color: Colors.white, fontSize: 10),
              ),
              Text(
                'Buffer: ${metrics.bufferDurationMs}ms',
                style: TextStyle(color: Colors.white, fontSize: 10),
              ),
              Text(
                'Quality: ${metrics.bufferDurationMs}/100',
                style: TextStyle(color: Colors.white, fontSize: 10),
              ),
            ],
          ),
        ),
      ),
  ],
);

}

@override void dispose() { _controller.removeListener(_onPlayerStateChanged); _controller.dispose(); super.dispose(); } } */

// ============================================ // BEST PRACTICES // ============================================

/*

  1. ALWAYS use ref.watch() for providers in build() ❌ Bad: final service = ServicesService() ✅ Good: final service = ref.read(serviceProvider)

  2. DISPOSE resources properly ❌ Bad: Forget to cancel timers ✅ Good: Override dispose() and clean up

  3. HANDLE network errors gracefully ❌ Bad: Assume network always works ✅ Good: Use try-catch with retry logic

  4. OPTIMIZE images ❌ Bad: Load full resolution images ✅ Good: Use cached_network_image with cache manager

  5. MONITOR memory usage ❌ Bad: Keep unlimited cache ✅ Good: Use cache service with auto-eviction

  6. TEST on low-end devices ❌ Bad: Only test on flagship phones ✅ Good: Test on Android 6.0 with 1GB RAM

  7. MEASURE performance ❌ Bad: "It feels fast" ✅ Good: Use metrics to measure and improve */