Files
neomovies-mobile/lib/presentation/providers/downloads_provider.dart
Cursor Agent 185980083a feat: add comprehensive logging for downloads debugging
Added extensive logging throughout DownloadsProvider and DownloadsScreen
to diagnose why downloads screen appears empty.

DownloadsProvider.refreshDownloads():
- 📥 Log function call
- 📥 Log state changes (loading, error)
- 📥 Log TorrentPlatformService.getAllDownloads() call
- 📥 Log number of torrents received
- 📥 Log each torrent processing with index
- 📥 Log success/failure for each torrent info fetch
- 📥 Log final torrents count
- 📥 Log completion or error state

DownloadsScreen.initState() and Consumer:
- 📥 Log initState call
- 📥 Log postFrameCallback execution
- 📥 Log Consumer builder invocations
- 📥 Log provider state (isLoading, error, torrents.length)
- 📥 Log which UI is displayed:
  * CircularProgressIndicator
  * ErrorDisplay
  * Empty state message
  * Torrent list with count

All logs prefixed with 📥 for easy filtering in logcat.

Example output:
---
📥 DownloadsScreen: initState() called
📥 DownloadsScreen: postFrameCallback, calling refreshDownloads()
📥 DownloadsProvider: refreshDownloads() called
📥 Setting loading=true, error=null
📥 Calling TorrentPlatformService.getAllDownloads()...
📥 Got 0 torrents from platform service
📥 Cleared _torrents list
📥 Final torrents count: 0
📥 Setting loading=false
📥  refreshDownloads() completed successfully
📥 DownloadsScreen: Consumer builder called
📥   isLoading: false
📥   error: null
📥   torrents.length: 0
📥   → Showing empty state

This will help identify:
- Is refreshDownloads being called?
- Does TorrentPlatformService return any data?
- Are torrents parsed correctly?
- Is the correct UI state shown?
- Where does the process fail?

Usage:
Run app → Open Downloads screen → Check logcat for 📥 logs
2025-10-05 17:35:07 +00:00

190 lines
6.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:flutter/foundation.dart';
import '../../data/services/torrent_platform_service.dart';
import '../../data/models/torrent_info.dart';
/// Provider для управления загрузками торрентов
class DownloadsProvider with ChangeNotifier {
final List<TorrentInfo> _torrents = [];
Timer? _progressTimer;
bool _isLoading = false;
String? _error;
String? _stackTrace;
List<TorrentInfo> get torrents => List.unmodifiable(_torrents);
bool get isLoading => _isLoading;
String? get error => _error;
String? get stackTrace => _stackTrace;
DownloadsProvider() {
_startProgressUpdates();
}
@override
void dispose() {
_progressTimer?.cancel();
super.dispose();
}
void _startProgressUpdates() {
_progressTimer = Timer.periodic(const Duration(seconds: 3), (timer) {
if (_torrents.isNotEmpty && !_isLoading) {
refreshDownloads();
}
});
}
/// Загрузить список активных загрузок
Future<void> refreshDownloads() async {
print('📥 DownloadsProvider: refreshDownloads() called');
try {
print('📥 Setting loading=true, error=null');
_setLoading(true);
_setError(null);
print('📥 Calling TorrentPlatformService.getAllDownloads()...');
final progress = await TorrentPlatformService.getAllDownloads();
print('📥 Got ${progress.length} torrents from platform service');
// Получаем полную информацию о каждом торренте
_torrents.clear();
print('📥 Cleared _torrents list');
for (int i = 0; i < progress.length; i++) {
final progressItem = progress[i];
print('📥 Processing torrent $i: ${progressItem.infoHash.substring(0, 8)}...');
try {
final torrentInfo = await TorrentPlatformService.getTorrent(progressItem.infoHash);
if (torrentInfo != null) {
_torrents.add(torrentInfo);
}
} catch (e) {
// Если не удалось получить полную информацию, создаем базовую
_torrents.add(TorrentInfo(
infoHash: progressItem.infoHash,
name: 'Торрент ${progressItem.infoHash.substring(0, 8)}',
totalSize: 0,
progress: progressItem.progress,
downloadSpeed: progressItem.downloadRate,
uploadSpeed: progressItem.uploadRate,
numSeeds: progressItem.numSeeds,
numPeers: progressItem.numPeers,
state: progressItem.state,
savePath: '/storage/emulated/0/Download/NeoMovies',
files: [],
);
print('📥 ✅ Created basic info: ${basicInfo.name}');
_torrents.add(basicInfo);
}
}
print('📥 Final torrents count: ${_torrents.length}');
print('📥 Setting loading=false');
_setLoading(false);
print('📥 ✅ refreshDownloads() completed successfully');
} catch (e, stackTrace) {
print('📥 ❌ Error refreshing downloads: $e');
print('📥 Stack trace: $stackTrace');
_setError(e.toString(), stackTrace.toString());
_setLoading(false);
print('📥 Error state set, loading=false');
}
}
/// Получить информацию о конкретном торренте
Future<TorrentInfo?> getTorrentInfo(String infoHash) async {
try {
return await TorrentPlatformService.getTorrent(infoHash);
} catch (e) {
debugPrint('Ошибка получения информации о торренте: $e');
return null;
}
}
/// Приостановить торрент
Future<void> pauseTorrent(String infoHash) async {
try {
await TorrentPlatformService.pauseDownload(infoHash);
await refreshDownloads(); // Обновляем список
} catch (e) {
_setError(e.toString());
}
}
/// Возобновить торрент
Future<void> resumeTorrent(String infoHash) async {
try {
await TorrentPlatformService.resumeDownload(infoHash);
await refreshDownloads(); // Обновляем список
} catch (e) {
_setError(e.toString());
}
}
/// Удалить торрент
Future<void> removeTorrent(String infoHash) async {
try {
await TorrentPlatformService.cancelDownload(infoHash);
await refreshDownloads(); // Обновляем список
} catch (e) {
_setError(e.toString());
}
}
/// Установить приоритет файла
Future<void> setFilePriority(String infoHash, int fileIndex, FilePriority priority) async {
try {
await TorrentPlatformService.setFilePriority(infoHash, fileIndex, priority);
} catch (e) {
_setError(e.toString());
}
}
/// Добавить новый торрент
Future<String?> addTorrent(String magnetUri, {String? savePath}) async {
try {
final infoHash = await TorrentPlatformService.addTorrent(
magnetUri: magnetUri,
savePath: savePath,
);
await refreshDownloads(); // Обновляем список
return infoHash;
} catch (e) {
_setError(e.toString());
return null;
}
}
/// Форматировать скорость
String formatSpeed(int bytesPerSecond) {
if (bytesPerSecond < 1024) return '${bytesPerSecond}B/s';
if (bytesPerSecond < 1024 * 1024) return '${(bytesPerSecond / 1024).toStringAsFixed(1)}KB/s';
return '${(bytesPerSecond / (1024 * 1024)).toStringAsFixed(1)}MB/s';
}
/// Форматировать продолжительность
String formatDuration(Duration duration) {
final hours = duration.inHours;
final minutes = duration.inMinutes.remainder(60);
final seconds = duration.inSeconds.remainder(60);
if (hours > 0) {
return '${hours}ч ${minutes}м ${seconds}с';
} else if (minutes > 0) {
return '${minutes}м ${seconds}с';
} else {
return '${seconds}с';
}
}
void _setLoading(bool loading) {
_isLoading = loading;
notifyListeners();
}
void _setError(String? error, [String? stackTrace]) {
_error = error;
_stackTrace = stackTrace;
notifyListeners();
}
}