Files
Zakaria 1563409cb1
Build / Build for Android (push) Has been cancelled
Build / Build for iOS (push) Has been cancelled
first commit
2026-05-18 14:15:38 -04:00

135 lines
5.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart';
import '../../models/finamp_models.dart';
import '../../services/downloads_helper.dart';
import '../../services/download_update_stream.dart';
import '../../models/jellyfin_models.dart';
import '../error_snackbar.dart';
class DownloadedIndicator extends StatefulWidget {
const DownloadedIndicator({
Key? key,
required this.item,
this.size,
}) : super(key: key);
final BaseItemDto item;
final double? size;
@override
State<DownloadedIndicator> createState() => _DownloadedIndicatorState();
}
class _DownloadedIndicatorState extends State<DownloadedIndicator> {
final _downloadsHelper = GetIt.instance<DownloadsHelper>();
final _downloadUpdateStream = GetIt.instance<DownloadUpdateStream>();
late Future<List<DownloadTask>?> _downloadedIndicatorFuture;
String? _downloadTaskId;
DownloadTaskStatus? _currentStatus;
@override
void initState() {
super.initState();
_downloadedIndicatorFuture =
_downloadsHelper.getDownloadStatus([widget.item.id]);
// We do this instead of using a StreamBuilder because the StreamBuilder
// kept dropping events. With this, we can also make it so that the widget
// only rebuilds when it actually has to.
_downloadUpdateStream.stream.listen((event) {
if (event.id == _downloadTaskId && event.status != _currentStatus) {
setState(() {
_currentStatus = event.status;
});
}
});
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<DownloadTask>?>(
future: _downloadedIndicatorFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data != null && snapshot.data!.isNotEmpty) {
_downloadTaskId = snapshot.data?[0].taskId;
_currentStatus = snapshot.data?[0].status;
}
// This ValueListenable is used to get the download task ID of new
// downloads. It also clears the task ID and status when the download
// is deleted. This only rebuilds when the item with key
// widget.item.id is changed, so this should only rebuild when the
// item is first downloaded and when it is deleted.
return ValueListenableBuilder<Box<DownloadedSong>>(
valueListenable: _downloadsHelper
.getDownloadedItemsListenable(keys: [widget.item.id]),
builder: (context, box, _) {
if (_downloadTaskId == null && box.get(widget.item.id) != null) {
_downloadTaskId = box.get(widget.item.id)!.downloadId;
} else if (box.get(widget.item.id) == null) {
_downloadTaskId = null;
_currentStatus = null;
}
// return StreamBuilder<DownloadUpdate>(
// stream: _downloadUpdateStream.stream,
// builder: (context, snapshot) {
// print("Streambuilder rebuild ${snapshot.data}");
// if (snapshot.hasData &&
// snapshot.data!.id == _downloadTask?.taskId) {
// print("Change $_currentStatus to ${snapshot.data?.status}");
// if (snapshot.data?.status == DownloadTaskStatus.complete) {
// print(
// "COMPLETE IN STREAMBUILDER ${widget.item.name}!!!!");
// }
// _currentStatus = snapshot.data?.status;
// }
if (_currentStatus == null) {
return const SizedBox.shrink();
} else if (_currentStatus == DownloadTaskStatus.complete) {
return Icon(
Icons.download,
color: Theme.of(context).colorScheme.secondary,
size: widget.size,
);
} else if (_currentStatus == DownloadTaskStatus.failed ||
_currentStatus == DownloadTaskStatus.undefined) {
return Icon(
Icons.error,
color: Colors.red,
size: widget.size,
);
} else if (_currentStatus == DownloadTaskStatus.paused) {
return Icon(
Icons.pause,
color: Colors.yellow,
size: widget.size,
);
} else if (_currentStatus == DownloadTaskStatus.enqueued ||
_currentStatus == DownloadTaskStatus.running) {
return Icon(
Icons.download_outlined,
color: Colors.white.withOpacity(0.5),
size: widget.size,
);
} else {
return const SizedBox.shrink();
}
// },
// );
},
);
} else if (snapshot.hasError) {
errorSnackbar(snapshot.error, context);
return const SizedBox.shrink();
} else {
return const SizedBox.shrink();
}
},
);
}
}