Initial implementation of hashtag tracking and auto-complete

codemagic-setup
Hank Grabowski 2022-12-28 17:04:48 -05:00
rodzic 45380df0d0
commit 7a41065a1c
5 zmienionych plików z 110 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import '../../globals.dart';
import '../../services/hashtag_service.dart';
class HashtagAutocompleteOptions extends StatelessWidget {
const HashtagAutocompleteOptions({
Key? key,
required this.query,
required this.onHashtagTap,
}) : super(key: key);
final String query;
final ValueSetter<String> onHashtagTap;
@override
Widget build(BuildContext context) {
final hashtags = getIt<HashtagService>().getMatchingHashTags(query);
if (hashtags.isEmpty) return const SizedBox.shrink();
return Card(
margin: const EdgeInsets.all(8),
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
clipBehavior: Clip.hardEdge,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
color: const Color(0xFFF7F7F8),
child: ListTile(
dense: true,
horizontalTitleGap: 0,
title: Text("Hashtags matching '$query'"),
),
),
LimitedBox(
maxHeight: MediaQuery.of(context).size.height * 0.2,
child: ListView.separated(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: hashtags.length,
separatorBuilder: (_, __) => const Divider(),
itemBuilder: (context, i) {
final hashtag = hashtags[i];
return GestureDetector(
onTap: () => onHashtagTap(hashtag),
child: Text(hashtag),
);
},
),
),
],
),
);
}
}

Wyświetl plik

@ -12,6 +12,7 @@ import 'services/auth_service.dart';
import 'services/connections_manager.dart';
import 'services/entry_manager_service.dart';
import 'services/gallery_service.dart';
import 'services/hashtag_service.dart';
import 'services/media_upload_attachment_helper.dart';
import 'services/notifications_manager.dart';
import 'services/secrets_service.dart';
@ -36,6 +37,7 @@ void main() async {
final timelineManager = TimelineManager();
final galleryService = GalleryService();
getIt.registerLazySingleton<ConnectionsManager>(() => ConnectionsManager());
getIt.registerLazySingleton<HashtagService>(() => HashtagService());
getIt.registerSingleton(galleryService);
getIt.registerSingleton<EntryManagerService>(entryManagerService);
getIt.registerSingleton<SecretsService>(secretsService);
@ -94,6 +96,10 @@ class App extends StatelessWidget {
create: (_) => getIt<GalleryService>(),
lazy: true,
),
ChangeNotifierProvider<HashtagService>(
create: (_) => getIt<HashtagService>(),
lazy: true,
),
ChangeNotifierProvider<TimelineManager>(
create: (_) => getIt<TimelineManager>(),
),

Wyświetl plik

@ -6,6 +6,7 @@ import 'package:multi_trigger_autocomplete/multi_trigger_autocomplete.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
import '../controls/autocomplete/hashtag_autocomplete_options.dart';
import '../controls/autocomplete/mention_autocomplete_options.dart';
import '../controls/entry_media_attachments/gallery_selector_control.dart';
import '../controls/entry_media_attachments/media_uploads_control.dart';
@ -187,6 +188,18 @@ class _EditorScreenState extends State<EditorScreen> {
);
},
),
AutocompleteTrigger(
trigger: '#',
optionsViewBuilder: (context, autocompleteQuery, controller) {
return HashtagAutocompleteOptions(
query: autocompleteQuery.query,
onHashtagTap: (hashtag) {
final autocomplete = MultiTriggerAutocomplete.of(context);
return autocomplete.acceptAutocompleteOption(hashtag);
},
);
},
),
],
fieldViewBuilder: (context, controller, focusNode) => TextFormField(
focusNode: focusNode,

Wyświetl plik

@ -7,6 +7,7 @@ import '../../models/location_data.dart';
import '../../models/media_attachment.dart';
import '../../models/timeline_entry.dart';
import '../../services/connections_manager.dart';
import '../../services/hashtag_service.dart';
import '../../utils/dateutils.dart';
import 'connection_mastodon_extensions.dart';
@ -71,6 +72,15 @@ extension TimelineEntryMastodonExtensions on TimelineEntry {
reshareAuthor = '';
}
final List<dynamic>? tags = json['tags'];
if (tags?.isNotEmpty ?? false) {
final tagManager = getIt<HashtagService>();
for (final tag in tags!) {
final tagName = tag['name'];
tagManager.addHashtage(tagName);
}
}
return TimelineEntry(
creationTimestamp: timestamp,
modificationTimestamp: modificationTimestamp,

Wyświetl plik

@ -0,0 +1,21 @@
import 'package:flutter/foundation.dart';
class HashtagService extends ChangeNotifier {
final _hashTags = <String>{};
void clear() {
_hashTags.clear();
notifyListeners();
}
void addHashtage(String hashtag) {
_hashTags.add(hashtag);
notifyListeners();
}
List<String> getMatchingHashTags(String searchString) {
return _hashTags
.where((tag) => tag.toLowerCase().contains(searchString.toLowerCase()))
.toList();
}
}