mirror of
https://gitlab.com/foxixus/neomovies_mobile.git
synced 2025-10-28 03:58:50 +05:00
feat: Implement comprehensive torrent downloads management system
- Fix torrent platform service integration with Android engine - Add downloads page with torrent list and progress tracking - Implement torrent detail screen with file selection and priorities - Create native video player with fullscreen controls - Add WebView players for Vibix and Alloha - Integrate corrected torrent engine with file selector - Update dependencies for auto_route and video players Features: ✅ Downloads screen with real-time torrent status ✅ File-level priority management and selection ✅ Three player options: native, Vibix WebView, Alloha WebView ✅ Torrent pause/resume/remove functionality ✅ Progress tracking and seeder/peer counts ✅ Video file detection and playback integration ✅ Fixed Android torrent engine method calls This resolves torrent integration issues and provides complete downloads management UI with video playback capabilities.
This commit is contained in:
180
lib/data/models/torrent_info.dart
Normal file
180
lib/data/models/torrent_info.dart
Normal file
@@ -0,0 +1,180 @@
|
||||
/// File priority enum matching Android implementation
|
||||
enum FilePriority {
|
||||
DONT_DOWNLOAD(0),
|
||||
NORMAL(4),
|
||||
HIGH(7);
|
||||
|
||||
const FilePriority(this.value);
|
||||
final int value;
|
||||
|
||||
static FilePriority fromValue(int value) {
|
||||
return FilePriority.values.firstWhere(
|
||||
(priority) => priority.value == value,
|
||||
orElse: () => FilePriority.NORMAL,
|
||||
);
|
||||
}
|
||||
|
||||
bool operator >(FilePriority other) => value > other.value;
|
||||
bool operator <(FilePriority other) => value < other.value;
|
||||
bool operator >=(FilePriority other) => value >= other.value;
|
||||
bool operator <=(FilePriority other) => value <= other.value;
|
||||
}
|
||||
|
||||
/// Torrent file information matching Android TorrentFileInfo
|
||||
class TorrentFileInfo {
|
||||
final String path;
|
||||
final int size;
|
||||
final FilePriority priority;
|
||||
final double progress;
|
||||
|
||||
TorrentFileInfo({
|
||||
required this.path,
|
||||
required this.size,
|
||||
required this.priority,
|
||||
this.progress = 0.0,
|
||||
});
|
||||
|
||||
factory TorrentFileInfo.fromAndroidJson(Map<String, dynamic> json) {
|
||||
return TorrentFileInfo(
|
||||
path: json['path'] as String,
|
||||
size: json['size'] as int,
|
||||
priority: FilePriority.fromValue(json['priority'] as int),
|
||||
progress: (json['progress'] as num?)?.toDouble() ?? 0.0,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'path': path,
|
||||
'size': size,
|
||||
'priority': priority.value,
|
||||
'progress': progress,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Main torrent information class matching Android TorrentInfo
|
||||
class TorrentInfo {
|
||||
final String infoHash;
|
||||
final String name;
|
||||
final int totalSize;
|
||||
final double progress;
|
||||
final int downloadSpeed;
|
||||
final int uploadSpeed;
|
||||
final int numSeeds;
|
||||
final int numPeers;
|
||||
final String state;
|
||||
final String savePath;
|
||||
final List<TorrentFileInfo> files;
|
||||
final int pieceLength;
|
||||
final int numPieces;
|
||||
final DateTime? addedTime;
|
||||
|
||||
TorrentInfo({
|
||||
required this.infoHash,
|
||||
required this.name,
|
||||
required this.totalSize,
|
||||
required this.progress,
|
||||
required this.downloadSpeed,
|
||||
required this.uploadSpeed,
|
||||
required this.numSeeds,
|
||||
required this.numPeers,
|
||||
required this.state,
|
||||
required this.savePath,
|
||||
required this.files,
|
||||
this.pieceLength = 0,
|
||||
this.numPieces = 0,
|
||||
this.addedTime,
|
||||
});
|
||||
|
||||
factory TorrentInfo.fromAndroidJson(Map<String, dynamic> json) {
|
||||
final filesJson = json['files'] as List<dynamic>? ?? [];
|
||||
final files = filesJson
|
||||
.map((fileJson) => TorrentFileInfo.fromAndroidJson(fileJson as Map<String, dynamic>))
|
||||
.toList();
|
||||
|
||||
return TorrentInfo(
|
||||
infoHash: json['infoHash'] as String,
|
||||
name: json['name'] as String,
|
||||
totalSize: json['totalSize'] as int,
|
||||
progress: (json['progress'] as num).toDouble(),
|
||||
downloadSpeed: json['downloadSpeed'] as int,
|
||||
uploadSpeed: json['uploadSpeed'] as int,
|
||||
numSeeds: json['numSeeds'] as int,
|
||||
numPeers: json['numPeers'] as int,
|
||||
state: json['state'] as String,
|
||||
savePath: json['savePath'] as String,
|
||||
files: files,
|
||||
pieceLength: json['pieceLength'] as int? ?? 0,
|
||||
numPieces: json['numPieces'] as int? ?? 0,
|
||||
addedTime: json['addedTime'] != null
|
||||
? DateTime.fromMillisecondsSinceEpoch(json['addedTime'] as int)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'infoHash': infoHash,
|
||||
'name': name,
|
||||
'totalSize': totalSize,
|
||||
'progress': progress,
|
||||
'downloadSpeed': downloadSpeed,
|
||||
'uploadSpeed': uploadSpeed,
|
||||
'numSeeds': numSeeds,
|
||||
'numPeers': numPeers,
|
||||
'state': state,
|
||||
'savePath': savePath,
|
||||
'files': files.map((file) => file.toJson()).toList(),
|
||||
'pieceLength': pieceLength,
|
||||
'numPieces': numPieces,
|
||||
'addedTime': addedTime?.millisecondsSinceEpoch,
|
||||
};
|
||||
}
|
||||
|
||||
/// Get video files only
|
||||
List<TorrentFileInfo> get videoFiles {
|
||||
final videoExtensions = {'.mp4', '.mkv', '.avi', '.mov', '.wmv', '.flv', '.webm', '.m4v'};
|
||||
return files.where((file) {
|
||||
final extension = file.path.toLowerCase().split('.').last;
|
||||
return videoExtensions.contains('.$extension');
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/// Get the largest video file (usually the main movie file)
|
||||
TorrentFileInfo? get mainVideoFile {
|
||||
final videos = videoFiles;
|
||||
if (videos.isEmpty) return null;
|
||||
|
||||
videos.sort((a, b) => b.size.compareTo(a.size));
|
||||
return videos.first;
|
||||
}
|
||||
|
||||
/// Check if torrent is completed
|
||||
bool get isCompleted => progress >= 1.0;
|
||||
|
||||
/// Check if torrent is downloading
|
||||
bool get isDownloading => state == 'DOWNLOADING';
|
||||
|
||||
/// Check if torrent is seeding
|
||||
bool get isSeeding => state == 'SEEDING';
|
||||
|
||||
/// Check if torrent is paused
|
||||
bool get isPaused => state == 'PAUSED';
|
||||
|
||||
/// Get formatted download speed
|
||||
String get formattedDownloadSpeed => _formatBytes(downloadSpeed);
|
||||
|
||||
/// Get formatted upload speed
|
||||
String get formattedUploadSpeed => _formatBytes(uploadSpeed);
|
||||
|
||||
/// Get formatted total size
|
||||
String get formattedTotalSize => _formatBytes(totalSize);
|
||||
|
||||
static String _formatBytes(int bytes) {
|
||||
if (bytes < 1024) return '${bytes}B';
|
||||
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}KB';
|
||||
if (bytes < 1024 * 1024 * 1024) return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}MB';
|
||||
return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(1)}GB';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user