[verified] Publish ReelBox source under GPLv3
This commit is contained in:
commit
db2b505ca3
445 files changed
+105274
No files matched your search
@@ -0,0 +1,97 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/models.dart';
|
||||
import '../state/app_state.dart';
|
||||
import 'download_service.dart';
|
||||
import 'downloads_page.dart';
|
||||
|
||||
typedef EnqueueDownload = Future<void> Function({
|
||||
required TitleRecord title,
|
||||
required MediaSource source,
|
||||
EpisodeRecord? episode,
|
||||
});
|
||||
|
||||
/// The primary action always queues inside Reelbox, never an external app.
|
||||
class DownloadButton extends StatefulWidget {
|
||||
const DownloadButton({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.source,
|
||||
this.episode,
|
||||
this.enqueue,
|
||||
this.openDownloads,
|
||||
});
|
||||
|
||||
final TitleRecord title;
|
||||
final MediaSource source;
|
||||
final EpisodeRecord? episode;
|
||||
final EnqueueDownload? enqueue;
|
||||
final void Function(BuildContext context)? openDownloads;
|
||||
|
||||
@override
|
||||
State<DownloadButton> createState() => _DownloadButtonState();
|
||||
}
|
||||
|
||||
class _DownloadButtonState extends State<DownloadButton> {
|
||||
bool _starting = false;
|
||||
|
||||
Future<void> _download() async {
|
||||
if (_starting) return;
|
||||
setState(() => _starting = true);
|
||||
try {
|
||||
final host = Uri.tryParse(widget.source.url)?.host.toLowerCase() ?? '';
|
||||
if (RegExp(
|
||||
'youtube|embed',
|
||||
caseSensitive: false,
|
||||
).hasMatch(widget.source.type) ||
|
||||
host == 'youtu.be' ||
|
||||
host == 'youtube.com' ||
|
||||
host.endsWith('.youtube.com')) {
|
||||
throw UnsupportedError(
|
||||
tr(
|
||||
context,
|
||||
'Embedded sources cannot be downloaded. Choose a direct media source.',
|
||||
'منابع جاسازیشده قابل دانلود نیستند. یک منبع رسانه مستقیم انتخاب کنید.',
|
||||
),
|
||||
);
|
||||
}
|
||||
await (widget.enqueue ?? DownloadService.instance.enqueue)(
|
||||
title: widget.title,
|
||||
source: widget.source,
|
||||
episode: widget.episode,
|
||||
);
|
||||
if (!mounted) return;
|
||||
if (widget.openDownloads case final open?) {
|
||||
open(context);
|
||||
} else {
|
||||
Navigator.of(
|
||||
context,
|
||||
).push(MaterialPageRoute<void>(builder: (_) => const DownloadsPage()));
|
||||
}
|
||||
} catch (error) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'${tr(context, 'Could not start download', 'شروع دانلود ممکن نشد')}: ${downloadErrorMessage(error)}',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) setState(() => _starting = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => FilledButton.icon(
|
||||
onPressed: widget.source.url.isEmpty || _starting ? null : _download,
|
||||
icon: _starting
|
||||
? const SizedBox.square(
|
||||
dimension: 18,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Icon(Icons.download_outlined),
|
||||
label: Text(tr(context, 'Download in Reelbox', 'دانلود در ریلباکس')),
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user