Update changelog noting fixes for #36 also help fix #62

merge-requests/67/merge
Hank Grabowski 2024-06-28 09:50:04 -04:00
rodzic 8c6aa6fee7
commit 40eed4a5d5
7 zmienionych plików z 88 dodań i 11 usunięć

Wyświetl plik

@ -38,7 +38,9 @@
* Ability to turn off Spoiler Alert/CWs at the application
level. Defaults to on. ([Feature #42](https://gitlab.com/mysocialportal/relatica/-/issues/42))
* Throws a confirm dialog box up if adding a comment to a post/comment over 30 days
old. ([Feature #58](https://gitlab.com/mysocialportal/relatica/-/issues/58))
old. ([Feature #58](https://gitlab.com/mysocialportal/relatica/-/issues/58))
* Autocomplete now lists hashtags and accounts that are used in a post or post above the rest of the
results. ([Feature #28](https://gitlab.com/mysocialportal/relatica/-/issues/28))
## Version 0.10.1 (beta)

Wyświetl plik

@ -1,21 +1,34 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../globals.dart';
import '../../services/entry_manager_service.dart';
import '../../services/hashtag_service.dart';
import '../../utils/active_profile_selector.dart';
class HashtagAutocompleteOptions extends StatelessWidget {
const HashtagAutocompleteOptions({
super.key,
required this.id,
required this.query,
required this.onHashtagTap,
});
final String id;
final String query;
final ValueSetter<String> onHashtagTap;
@override
Widget build(BuildContext context) {
final hashtags = getIt<HashtagService>().getMatchingHashTags(query);
final manager = context
.read<ActiveProfileSelector<EntryManagerService>>()
.activeEntry
.value;
final postTreeHashtags =
manager.getPostTreeHashtags(id).getValueOrElse(() => [])..sort();
final hashtagsFromService =
getIt<HashtagService>().getMatchingHashTags(query);
final hashtags = [...postTreeHashtags, ...hashtagsFromService];
if (hashtags.isEmpty) return const SizedBox.shrink();

Wyświetl plik

@ -1,9 +1,10 @@
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import '../../globals.dart';
import '../../models/connection.dart';
import '../../services/connections_manager.dart';
import '../../services/entry_manager_service.dart';
import '../../utils/active_profile_selector.dart';
import '../image_control.dart';
@ -12,24 +13,39 @@ class MentionAutocompleteOptions extends StatelessWidget {
const MentionAutocompleteOptions({
super.key,
required this.id,
required this.query,
required this.onMentionUserTap,
});
final String id;
final String query;
final ValueSetter<Connection> onMentionUserTap;
@override
Widget build(BuildContext context) {
final users = getIt<ActiveProfileSelector<ConnectionsManager>>()
final entryManager = context
.read<ActiveProfileSelector<EntryManagerService>>()
.activeEntry
.andThenSuccess((manager) => manager.getKnownUsersByName(query))
.fold(
onSuccess: (users) => users,
onError: (error) {
_logger.severe('Error getting users list: $error');
return [];
});
.value;
final connectionManager = context
.read<ActiveProfileSelector<ConnectionsManager>>()
.activeEntry
.value;
final postTreeUsers = entryManager
.getPostTreeConnectionIds(id)
.getValueOrElse(() => [])
.map((id) => connectionManager.getById(id))
.where((result) => result.isSuccess)
.map((result) => result.value)
.toList()
..sort((u1, u2) => u1.name.compareTo(u2.name));
final knownUsers = connectionManager.getKnownUsersByName(query);
final users = [...postTreeUsers, ...knownUsers];
if (users.isEmpty) return const SizedBox.shrink();

Wyświetl plik

@ -333,6 +333,7 @@ class _EditorScreenState extends State<EditorScreen> {
trigger: '@',
optionsViewBuilder: (context, autocompleteQuery, controller) {
return MentionAutocompleteOptions(
id: parentEntry?.id ?? '',
query: autocompleteQuery.query,
onMentionUserTap: (user) {
final autocomplete = MultiTriggerAutocomplete.of(context);
@ -345,6 +346,7 @@ class _EditorScreenState extends State<EditorScreen> {
trigger: '#',
optionsViewBuilder: (context, autocompleteQuery, controller) {
return HashtagAutocompleteOptions(
id: parentEntry?.id ?? '',
query: autocompleteQuery.query,
onHashtagTap: (hashtag) {
final autocomplete = MultiTriggerAutocomplete.of(context);

Wyświetl plik

@ -407,6 +407,7 @@ class _FilterEditorScreenState extends State<FilterEditorScreen> {
optionsViewBuilder:
(ovbContext, autocompleteQuery, controller) {
return MentionAutocompleteOptions(
id: '',
query: autocompleteQuery.query,
onMentionUserTap: (user) {
final autocomplete =
@ -480,6 +481,7 @@ class _FilterEditorScreenState extends State<FilterEditorScreen> {
optionsViewBuilder:
(ovbContext, autocompleteQuery, controller) {
return HashtagAutocompleteOptions(
id: '',
query: autocompleteQuery.query,
onHashtagTap: (hashtag) {
final autocomplete =

Wyświetl plik

@ -49,6 +49,7 @@ class MessagesNewThread extends StatelessWidget {
trigger: '@',
optionsViewBuilder: (context, autocompleteQuery, controller) {
return MentionAutocompleteOptions(
id: '',
query: autocompleteQuery.query,
onMentionUserTap: (user) {
final autocomplete =

Wyświetl plik

@ -23,6 +23,8 @@ class EntryManagerService extends ChangeNotifier {
final _entries = <String, TimelineEntry>{};
final _parentPostIds = <String, String>{};
final _postNodes = <String, _Node>{};
final _postThreadHashtags = <String, Set<String>>{};
final _postTreeConnections = <String, Set<String>>{};
final Profile profile;
EntryManagerService(this.profile);
@ -61,6 +63,32 @@ class EntryManagerService extends ChangeNotifier {
return Result.ok(_nodeToTreeItem(postNode, profile.userId));
}
Result<List<String>, ExecError> getPostTreeHashtags(String id) {
final postId = _getPostRootNode(id)?.id ?? '';
if (postId.isEmpty) {
return buildErrorResult(
type: ErrorType.notFound,
message: 'Root Post ID not found for $id',
);
}
final hashtags = _postThreadHashtags[postId]?.toList() ?? [];
return Result.ok(hashtags);
}
Result<List<String>, ExecError> getPostTreeConnectionIds(String id) {
final postId = _getPostRootNode(id)?.id ?? '';
if (postId.isEmpty) {
return buildErrorResult(
type: ErrorType.notFound,
message: 'Root Post ID not found for $id',
);
}
final hashtags = _postTreeConnections[postId]?.toList() ?? [];
return Result.ok(hashtags);
}
Result<TimelineEntry, ExecError> getEntryById(String id) {
if (_entries.containsKey(id)) {
return Result.ok(_entries[id]!);
@ -353,6 +381,11 @@ class EntryManagerService extends ChangeNotifier {
if (item.parentId.isEmpty) {
final postNode =
_postNodes.putIfAbsent(item.id, () => _Node(item.id));
final pth = _postThreadHashtags.putIfAbsent(item.id, () => {});
final ptc = _postTreeConnections.putIfAbsent(item.id, () => {});
pth.addAll(item.tags);
ptc.add(item.authorId);
ptc.add(item.parentAuthorId);
postNodesToReturn.add(postNode);
allSeenItems.remove(item);
} else {
@ -364,6 +397,14 @@ class EntryManagerService extends ChangeNotifier {
'Error finding parent ${item.parentId} for entry ${item.id}');
continue;
}
final pth =
_postThreadHashtags.putIfAbsent(parentParentPostId!, () => {});
final ptc =
_postTreeConnections.putIfAbsent(parentParentPostId, () => {});
pth.addAll(item.tags);
ptc.add(item.authorId);
ptc.add(item.parentAuthorId);
final parentPostNode = _postNodes[parentParentPostId]!;
postNodesToReturn.add(parentPostNode);
_parentPostIds[item.id] = parentPostNode.id;