You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
9.1 KiB
321 lines
9.1 KiB
1 year ago
|
import 'dart:async';
|
||
|
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter/services.dart';
|
||
|
import 'package:neon/blocs.dart';
|
||
|
import 'package:neon/utils.dart';
|
||
|
import 'package:neon/widgets.dart';
|
||
|
import 'package:neon_news/l10n/localizations.dart';
|
||
|
import 'package:neon_news/neon_news.dart';
|
||
|
import 'package:nextcloud/news.dart' as news;
|
||
|
|
||
|
class NewsAddFeedDialog extends StatefulWidget {
|
||
|
const NewsAddFeedDialog({
|
||
|
required this.bloc,
|
||
|
this.folderID,
|
||
|
super.key,
|
||
|
});
|
||
|
|
||
|
final NewsBloc bloc;
|
||
|
final int? folderID;
|
||
|
|
||
|
@override
|
||
|
State<NewsAddFeedDialog> createState() => _NewsAddFeedDialogState();
|
||
|
}
|
||
|
|
||
|
class _NewsAddFeedDialogState extends State<NewsAddFeedDialog> {
|
||
|
final formKey = GlobalKey<FormState>();
|
||
|
final controller = TextEditingController();
|
||
|
|
||
|
news.Folder? folder;
|
||
|
|
||
|
void submit() {
|
||
|
if (formKey.currentState!.validate()) {
|
||
|
Navigator.of(context).pop((controller.text, widget.folderID ?? folder?.id));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
|
|
||
|
unawaited(
|
||
|
Clipboard.getData(Clipboard.kTextPlain).then((final clipboardContent) {
|
||
|
if (clipboardContent != null && clipboardContent.text != null) {
|
||
|
final uri = Uri.tryParse(clipboardContent.text!);
|
||
|
if (uri != null && (uri.scheme == 'http' || uri.scheme == 'https')) {
|
||
|
controller.text = clipboardContent.text!;
|
||
|
}
|
||
|
}
|
||
|
}),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void dispose() {
|
||
|
controller.dispose();
|
||
|
super.dispose();
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(final BuildContext context) => ResultBuilder<List<news.Folder>>.behaviorSubject(
|
||
|
subject: widget.bloc.folders,
|
||
|
builder: (final context, final folders) => NeonDialog(
|
||
|
title: Text(NewsLocalizations.of(context).feedAdd),
|
||
|
children: [
|
||
|
Form(
|
||
|
key: formKey,
|
||
|
child: Column(
|
||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||
|
children: [
|
||
|
TextFormField(
|
||
|
autofocus: true,
|
||
|
controller: controller,
|
||
|
decoration: const InputDecoration(
|
||
|
hintText: 'https://...',
|
||
|
),
|
||
|
keyboardType: TextInputType.url,
|
||
|
validator: (final input) => validateHttpUrl(context, input),
|
||
|
onFieldSubmitted: (final _) {
|
||
|
submit();
|
||
|
},
|
||
|
),
|
||
|
if (widget.folderID == null) ...[
|
||
|
Center(
|
||
|
child: NeonError(
|
||
|
folders.error,
|
||
|
onRetry: widget.bloc.refresh,
|
||
|
),
|
||
|
),
|
||
|
Center(
|
||
|
child: NeonLinearProgressIndicator(
|
||
|
visible: folders.isLoading,
|
||
|
),
|
||
|
),
|
||
|
if (folders.hasData) ...[
|
||
|
NewsFolderSelect(
|
||
|
folders: folders.requireData,
|
||
|
value: folder,
|
||
|
onChanged: (final f) {
|
||
|
setState(() {
|
||
|
folder = f;
|
||
|
});
|
||
|
},
|
||
|
),
|
||
|
],
|
||
|
],
|
||
|
ElevatedButton(
|
||
|
onPressed: folders.hasData ? submit : null,
|
||
|
child: Text(NewsLocalizations.of(context).feedAdd),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
class NewsCreateFolderDialog extends StatefulWidget {
|
||
|
const NewsCreateFolderDialog({
|
||
|
super.key,
|
||
|
});
|
||
|
|
||
|
@override
|
||
|
State<NewsCreateFolderDialog> createState() => _NewsCreateFolderDialogState();
|
||
|
}
|
||
|
|
||
|
class _NewsCreateFolderDialogState extends State<NewsCreateFolderDialog> {
|
||
|
final formKey = GlobalKey<FormState>();
|
||
|
|
||
|
final controller = TextEditingController();
|
||
|
|
||
|
@override
|
||
|
void dispose() {
|
||
|
controller.dispose();
|
||
|
super.dispose();
|
||
|
}
|
||
|
|
||
|
void submit() {
|
||
|
if (formKey.currentState!.validate()) {
|
||
|
Navigator.of(context).pop(controller.text);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(final BuildContext context) => NeonDialog(
|
||
|
title: Text(NewsLocalizations.of(context).folderCreate),
|
||
|
children: [
|
||
|
Form(
|
||
|
key: formKey,
|
||
|
child: Column(
|
||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||
|
children: [
|
||
|
TextFormField(
|
||
|
autofocus: true,
|
||
|
controller: controller,
|
||
|
decoration: InputDecoration(
|
||
|
hintText: NewsLocalizations.of(context).folderCreateName,
|
||
|
),
|
||
|
validator: (final input) => validateNotEmpty(context, input),
|
||
|
onFieldSubmitted: (final _) {
|
||
|
submit();
|
||
|
},
|
||
|
),
|
||
|
ElevatedButton(
|
||
|
onPressed: submit,
|
||
|
child: Text(NewsLocalizations.of(context).folderCreate),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
);
|
||
|
}
|
||
|
|
||
|
class NewsFeedShowURLDialog extends StatefulWidget {
|
||
|
const NewsFeedShowURLDialog({
|
||
|
required this.feed,
|
||
|
super.key,
|
||
|
});
|
||
|
|
||
|
final news.Feed feed;
|
||
|
|
||
|
@override
|
||
|
State<NewsFeedShowURLDialog> createState() => _NewsFeedShowURLDialogState();
|
||
|
}
|
||
|
|
||
|
class _NewsFeedShowURLDialogState extends State<NewsFeedShowURLDialog> {
|
||
|
@override
|
||
|
Widget build(final BuildContext context) => AlertDialog(
|
||
|
title: Text(widget.feed.url),
|
||
|
actions: [
|
||
|
ElevatedButton(
|
||
|
onPressed: () async {
|
||
|
await Clipboard.setData(
|
||
|
ClipboardData(
|
||
|
text: widget.feed.url,
|
||
|
),
|
||
|
);
|
||
|
if (mounted) {
|
||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||
|
SnackBar(
|
||
|
content: Text(NewsLocalizations.of(context).feedCopiedURL),
|
||
|
),
|
||
|
);
|
||
|
Navigator.of(context).pop();
|
||
|
}
|
||
|
},
|
||
|
child: Text(NewsLocalizations.of(context).feedCopyURL),
|
||
|
),
|
||
|
ElevatedButton(
|
||
|
onPressed: () {
|
||
|
Navigator.of(context).pop();
|
||
|
},
|
||
|
child: Text(NewsLocalizations.of(context).actionClose),
|
||
|
),
|
||
|
],
|
||
|
);
|
||
|
}
|
||
|
|
||
|
class NewsFeedUpdateErrorDialog extends StatefulWidget {
|
||
|
const NewsFeedUpdateErrorDialog({
|
||
|
required this.feed,
|
||
|
super.key,
|
||
|
});
|
||
|
|
||
|
final news.Feed feed;
|
||
|
|
||
|
@override
|
||
|
State<NewsFeedUpdateErrorDialog> createState() => _NewsFeedUpdateErrorDialogState();
|
||
|
}
|
||
|
|
||
|
class _NewsFeedUpdateErrorDialogState extends State<NewsFeedUpdateErrorDialog> {
|
||
|
@override
|
||
|
Widget build(final BuildContext context) => AlertDialog(
|
||
|
title: Text(widget.feed.lastUpdateError!),
|
||
|
actions: [
|
||
|
ElevatedButton(
|
||
|
onPressed: () async {
|
||
|
await Clipboard.setData(
|
||
|
ClipboardData(
|
||
|
text: widget.feed.lastUpdateError!,
|
||
|
),
|
||
|
);
|
||
|
if (mounted) {
|
||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||
|
SnackBar(
|
||
|
content: Text(NewsLocalizations.of(context).feedCopiedErrorMessage),
|
||
|
),
|
||
|
);
|
||
|
Navigator.of(context).pop();
|
||
|
}
|
||
|
},
|
||
|
child: Text(NewsLocalizations.of(context).feedCopyErrorMessage),
|
||
|
),
|
||
|
ElevatedButton(
|
||
|
onPressed: () {
|
||
|
Navigator.of(context).pop();
|
||
|
},
|
||
|
child: Text(NewsLocalizations.of(context).actionClose),
|
||
|
),
|
||
|
],
|
||
|
);
|
||
|
}
|
||
|
|
||
|
class NewsMoveFeedDialog extends StatefulWidget {
|
||
|
const NewsMoveFeedDialog({
|
||
|
required this.folders,
|
||
|
required this.feed,
|
||
|
super.key,
|
||
|
});
|
||
|
|
||
|
final List<news.Folder> folders;
|
||
|
final news.Feed feed;
|
||
|
|
||
|
@override
|
||
|
State<NewsMoveFeedDialog> createState() => _NewsMoveFeedDialogState();
|
||
|
}
|
||
|
|
||
|
class _NewsMoveFeedDialogState extends State<NewsMoveFeedDialog> {
|
||
|
final formKey = GlobalKey<FormState>();
|
||
|
|
||
|
news.Folder? folder;
|
||
|
|
||
|
void submit() {
|
||
|
if (formKey.currentState!.validate()) {
|
||
|
Navigator.of(context).pop([folder?.id]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(final BuildContext context) => NeonDialog(
|
||
|
title: Text(NewsLocalizations.of(context).feedMove),
|
||
|
children: [
|
||
|
Form(
|
||
|
key: formKey,
|
||
|
child: Column(
|
||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||
|
children: [
|
||
|
NewsFolderSelect(
|
||
|
folders: widget.folders,
|
||
|
value: widget.feed.folderId != null
|
||
|
? widget.folders.singleWhere((final folder) => folder.id == widget.feed.folderId)
|
||
|
: null,
|
||
|
onChanged: (final f) {
|
||
|
setState(() {
|
||
|
folder = f;
|
||
|
});
|
||
|
},
|
||
|
),
|
||
|
ElevatedButton(
|
||
|
onPressed: submit,
|
||
|
child: Text(NewsLocalizations.of(context).feedMove),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
);
|
||
|
}
|