Improved add links
This commit is contained in:
@@ -11,7 +11,9 @@ class AddLinkModel {
|
||||
final TextEditingController titleController;
|
||||
final TextEditingController descriptionController;
|
||||
bool markAsUnread;
|
||||
final List<String> tags;
|
||||
final TextEditingController tagsController;
|
||||
String? tagsError;
|
||||
List<String> tags;
|
||||
final TextEditingController notesController;
|
||||
|
||||
AddLinkModel({
|
||||
@@ -22,6 +24,8 @@ class AddLinkModel {
|
||||
required this.titleController,
|
||||
required this.descriptionController,
|
||||
this.markAsUnread = false,
|
||||
required this.tagsController,
|
||||
this.tagsError,
|
||||
required this.tags,
|
||||
required this.notesController,
|
||||
});
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:linkdy/utils/snackbar.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import 'package:linkdy/screens/links/provider/links.provider.dart';
|
||||
import 'package:linkdy/screens/links/model/add_link.model.dart';
|
||||
|
||||
import 'package:linkdy/models/data/tags.dart';
|
||||
import 'package:linkdy/utils/snackbar.dart';
|
||||
import 'package:linkdy/i18n/strings.g.dart';
|
||||
import 'package:linkdy/utils/process_modal.dart';
|
||||
import 'package:linkdy/models/data/post_bookmark.dart';
|
||||
@@ -30,6 +31,12 @@ FutureOr<ApiResponse<Bookmark>> addBookmark(AddBookmarkRef ref, PostBookmark new
|
||||
return result;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
FutureOr<ApiResponse<Tags>> getTags(GetTagsRef ref) async {
|
||||
final result = await ref.watch(apiClientProviderProvider)!.fetchTags();
|
||||
return result;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class AddLink extends _$AddLink {
|
||||
@override
|
||||
@@ -38,6 +45,7 @@ class AddLink extends _$AddLink {
|
||||
urlController: TextEditingController(),
|
||||
titleController: TextEditingController(),
|
||||
descriptionController: TextEditingController(),
|
||||
tagsController: TextEditingController(),
|
||||
tags: [],
|
||||
notesController: TextEditingController(),
|
||||
);
|
||||
@@ -86,7 +94,7 @@ class AddLink extends _$AddLink {
|
||||
isArchived: false,
|
||||
unread: state.markAsUnread,
|
||||
shared: false,
|
||||
tagNames: [],
|
||||
tagNames: state.tags.join(","),
|
||||
);
|
||||
|
||||
final processModal = ProcessModal();
|
||||
@@ -106,4 +114,23 @@ class AddLink extends _$AddLink {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void validateTagInput(String value) {
|
||||
if (value.contains(" ")) {
|
||||
state.tagsError = t.links.addLink.tagNoWhitespaces;
|
||||
} else {
|
||||
state.tagsError = null;
|
||||
}
|
||||
ref.notifyListeners();
|
||||
}
|
||||
|
||||
void setTags(List<String> tags) {
|
||||
state.tags = tags;
|
||||
ref.notifyListeners();
|
||||
}
|
||||
|
||||
void clearTagsController() {
|
||||
state.tagsController.clear();
|
||||
ref.notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +290,21 @@ class _AddBookmarkProviderElement
|
||||
PostBookmark get newBookmark => (origin as AddBookmarkProvider).newBookmark;
|
||||
}
|
||||
|
||||
String _$addLinkHash() => r'0e9fcd2cca9fa5e195072163a11ae09b7bbe903a';
|
||||
String _$getTagsHash() => r'feecc7515f9492838c4a9bccc7031f49713e6ebb';
|
||||
|
||||
/// See also [getTags].
|
||||
@ProviderFor(getTags)
|
||||
final getTagsProvider = AutoDisposeFutureProvider<ApiResponse<Tags>>.internal(
|
||||
getTags,
|
||||
name: r'getTagsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$getTagsHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef GetTagsRef = AutoDisposeFutureProviderRef<ApiResponse<Tags>>;
|
||||
String _$addLinkHash() => r'fd6e2629386254ace7ac7abeff0e566dda69575a';
|
||||
|
||||
/// See also [AddLink].
|
||||
@ProviderFor(AddLink)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:easy_autocomplete/easy_autocomplete.dart';
|
||||
|
||||
import 'package:linkdy/screens/links/provider/add_link.provider.dart';
|
||||
import 'package:linkdy/widgets/autocomplete_text_field.dart';
|
||||
import 'package:linkdy/widgets/section_label.dart';
|
||||
|
||||
import 'package:linkdy/i18n/strings.g.dart';
|
||||
@@ -49,6 +49,8 @@ class _ModalContent extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final provider = ref.watch(addLinkProvider);
|
||||
|
||||
final tags = ref.watch(getTagsProvider);
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
@@ -185,6 +187,86 @@ class _ModalContent extends ConsumerWidget {
|
||||
vertical: 24,
|
||||
),
|
||||
),
|
||||
if (tags.isLoading == false)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
if (provider.checkBookmark != null)
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: EasyAutocomplete(
|
||||
controller: provider.tagsController,
|
||||
onChanged: ref.read(addLinkProvider.notifier).validateTagInput,
|
||||
suggestions: tags.value?.content?.results?.map((t) => t.name!).toList() ?? [],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10),
|
||||
),
|
||||
),
|
||||
labelText: t.links.addLink.tags,
|
||||
errorText: provider.tagsError,
|
||||
),
|
||||
suggestionBuilder: (data) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Text(
|
||||
data,
|
||||
style: TextStyle(fontSize: 16, color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
onSubmitted: provider.tagsController.text != "" && provider.tagsError == null
|
||||
? (v) {
|
||||
ref.read(addLinkProvider.notifier).setTags([...provider.tags, v]);
|
||||
ref.read(addLinkProvider.notifier).clearTagsController();
|
||||
}
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
IconButton(
|
||||
onPressed: provider.tagsController.text != "" && provider.tagsError == null
|
||||
? () {
|
||||
ref
|
||||
.read(addLinkProvider.notifier)
|
||||
.setTags([...provider.tags, provider.tagsController.text]);
|
||||
ref.read(addLinkProvider.notifier).clearTagsController();
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.check_rounded),
|
||||
tooltip: t.links.addLink.addTag,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (provider.checkBookmark != null) const SizedBox(height: 16),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
child: provider.tags.isNotEmpty
|
||||
? ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: provider.tags.length,
|
||||
separatorBuilder: (context, index) => const SizedBox(width: 8),
|
||||
itemBuilder: (context, index) => InputChip(
|
||||
label: Text(provider.tags[index]),
|
||||
onDeleted: () => ref
|
||||
.read(addLinkProvider.notifier)
|
||||
.setTags(provider.tags.where((tag) => tag != provider.tags[index]).toList()),
|
||||
),
|
||||
)
|
||||
: Center(
|
||||
child: Text(
|
||||
t.links.addLink.noTagsAdded,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SectionLabel(
|
||||
label: t.links.addLink.others,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
|
||||
Reference in New Issue
Block a user