mirror of
https://gitlab.com/mysocialportal/relatica
synced 2024-10-18 12:23:31 +00:00
Add real hashtag processing and storage
This commit is contained in:
parent
2a3c2296a1
commit
fa1609bdc3
10 changed files with 230 additions and 18 deletions
10
README.md
10
README.md
|
@ -2,7 +2,15 @@
|
|||
|
||||
A Flutter application for interfacing with the Friendica social network.
|
||||
|
||||
For Linux development be sure that libsecret-1-dev and libjsoncpp-dev are installed on the machine. For running only make sure the non-dev versions are...
|
||||
For Linux development be sure that libsecret-1-dev and libjsoncpp-dev are installed on the machine. For running only
|
||||
make sure the non-dev versions are...
|
||||
|
||||
## Development Notes
|
||||
|
||||
Whenever a model is changed that is stored in ObjectBox it is necessary to execute the command:
|
||||
|
||||
```bash
|
||||
flutter pub run build_runner build
|
||||
```
|
||||
|
||||
Licensed with the Mozilla Public License 2.0 copyleft license.
|
||||
|
|
11
lib/data/interfaces/hashtag_repo_intf.dart
Normal file
11
lib/data/interfaces/hashtag_repo_intf.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
import '../../models/hashtag.dart';
|
||||
|
||||
class IHashtagRepo {
|
||||
void add(Hashtag tag) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
List<String> getMatchingHashTags(String text) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
34
lib/data/objectbox/objectbox_hashtag_repo.dart
Normal file
34
lib/data/objectbox/objectbox_hashtag_repo.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
import '../../globals.dart';
|
||||
import '../../models/hashtag.dart';
|
||||
import '../../objectbox.g.dart';
|
||||
import '../interfaces/hashtag_repo_intf.dart';
|
||||
import 'objectbox_cache.dart';
|
||||
|
||||
class ObjectBoxHashtagRepo implements IHashtagRepo {
|
||||
late final Box<Hashtag> box;
|
||||
|
||||
ObjectBoxHashtagRepo() {
|
||||
box = getIt<ObjectBoxCache>().store.box<Hashtag>();
|
||||
}
|
||||
|
||||
@override
|
||||
void add(Hashtag tag) {
|
||||
box.putAsync(tag);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getMatchingHashTags(String text) {
|
||||
return (box
|
||||
.query(
|
||||
text.length <= 2
|
||||
? Hashtag_.tag.startsWith(text, caseSensitive: false)
|
||||
: Hashtag_.tag.contains(text, caseSensitive: false),
|
||||
)
|
||||
.order(Hashtag_.tag)
|
||||
.build()
|
||||
..limit = 100)
|
||||
.find()
|
||||
.map((h) => h.tag)
|
||||
.toList();
|
||||
}
|
||||
}
|
|
@ -7,9 +7,11 @@ import 'package:result_monad/result_monad.dart';
|
|||
|
||||
import 'data/interfaces/connections_repo_intf.dart';
|
||||
import 'data/interfaces/groups_repo.intf.dart';
|
||||
import 'data/interfaces/hashtag_repo_intf.dart';
|
||||
import 'data/memory/memory_groups_repo.dart';
|
||||
import 'data/objectbox/objectbox_cache.dart';
|
||||
import 'data/objectbox/objectbox_connections_repo.dart';
|
||||
import 'data/objectbox/objectbox_hashtag_repo.dart';
|
||||
import 'globals.dart';
|
||||
import 'models/TimelineIdentifiers.dart';
|
||||
import 'routes.dart';
|
||||
|
@ -54,6 +56,7 @@ void main() async {
|
|||
final objectBoxCache = await ObjectBoxCache.create();
|
||||
getIt.registerSingleton<ObjectBoxCache>(objectBoxCache);
|
||||
getIt.registerSingleton<IConnectionsRepo>(ObjectBoxConnectionsRepo());
|
||||
getIt.registerSingleton<IHashtagRepo>(ObjectBoxHashtagRepo());
|
||||
getIt.registerSingleton<IGroupsRepo>(MemoryGroupsRepo());
|
||||
getIt.registerLazySingleton<ConnectionsManager>(() => ConnectionsManager());
|
||||
getIt.registerLazySingleton<HashtagService>(() => HashtagService());
|
||||
|
|
30
lib/models/hashtag.dart
Normal file
30
lib/models/hashtag.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
import 'package:objectbox/objectbox.dart';
|
||||
|
||||
@Entity()
|
||||
class Hashtag {
|
||||
@Id()
|
||||
int id;
|
||||
|
||||
@Unique(onConflict: ConflictStrategy.replace)
|
||||
String tag;
|
||||
|
||||
String url;
|
||||
|
||||
@Property(type: PropertyType.date)
|
||||
DateTime lastUpdateTime;
|
||||
|
||||
Hashtag({
|
||||
this.id = 0,
|
||||
required this.tag,
|
||||
required this.url,
|
||||
DateTime? updateTime,
|
||||
}) : lastUpdateTime = updateTime ?? DateTime.now();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is Hashtag && runtimeType == other.runtimeType && tag == other.tag;
|
||||
|
||||
@override
|
||||
int get hashCode => tag.hashCode;
|
||||
}
|
|
@ -58,10 +58,41 @@
|
|||
}
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
{
|
||||
"id": "2:8060242331335522964",
|
||||
"lastPropertyId": "4:985152873657204249",
|
||||
"name": "Hashtag",
|
||||
"properties": [
|
||||
{
|
||||
"id": "1:3633001791521338712",
|
||||
"name": "id",
|
||||
"type": 6,
|
||||
"flags": 1
|
||||
},
|
||||
{
|
||||
"id": "2:3468373950035339457",
|
||||
"name": "tag",
|
||||
"type": 9,
|
||||
"flags": 34848,
|
||||
"indexId": "2:6156017341759176249"
|
||||
},
|
||||
{
|
||||
"id": "3:5102584273729210526",
|
||||
"name": "url",
|
||||
"type": 9
|
||||
},
|
||||
{
|
||||
"id": "4:985152873657204249",
|
||||
"name": "lastUpdateTime",
|
||||
"type": 10
|
||||
}
|
||||
],
|
||||
"relations": []
|
||||
}
|
||||
],
|
||||
"lastEntityId": "1:1213035855270739890",
|
||||
"lastIndexId": "1:8342366639839511243",
|
||||
"lastEntityId": "2:8060242331335522964",
|
||||
"lastIndexId": "2:6156017341759176249",
|
||||
"lastRelationId": "0:0",
|
||||
"lastSequenceId": "0:0",
|
||||
"modelVersion": 5,
|
||||
|
|
|
@ -15,6 +15,7 @@ import 'package:objectbox/objectbox.dart';
|
|||
import 'package:objectbox_flutter_libs/objectbox_flutter_libs.dart';
|
||||
|
||||
import 'models/connection.dart';
|
||||
import 'models/hashtag.dart';
|
||||
|
||||
export 'package:objectbox/objectbox.dart'; // so that callers only have to import this file
|
||||
|
||||
|
@ -73,6 +74,36 @@ final _entities = <ModelEntity>[
|
|||
flags: 0)
|
||||
],
|
||||
relations: <ModelRelation>[],
|
||||
backlinks: <ModelBacklink>[]),
|
||||
ModelEntity(
|
||||
id: const IdUid(2, 8060242331335522964),
|
||||
name: 'Hashtag',
|
||||
lastPropertyId: const IdUid(4, 985152873657204249),
|
||||
flags: 0,
|
||||
properties: <ModelProperty>[
|
||||
ModelProperty(
|
||||
id: const IdUid(1, 3633001791521338712),
|
||||
name: 'id',
|
||||
type: 6,
|
||||
flags: 1),
|
||||
ModelProperty(
|
||||
id: const IdUid(2, 3468373950035339457),
|
||||
name: 'tag',
|
||||
type: 9,
|
||||
flags: 34848,
|
||||
indexId: const IdUid(2, 6156017341759176249)),
|
||||
ModelProperty(
|
||||
id: const IdUid(3, 5102584273729210526),
|
||||
name: 'url',
|
||||
type: 9,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(4, 985152873657204249),
|
||||
name: 'lastUpdateTime',
|
||||
type: 10,
|
||||
flags: 0)
|
||||
],
|
||||
relations: <ModelRelation>[],
|
||||
backlinks: <ModelBacklink>[])
|
||||
];
|
||||
|
||||
|
@ -96,8 +127,8 @@ Future<Store> openStore(
|
|||
ModelDefinition getObjectBoxModel() {
|
||||
final model = ModelInfo(
|
||||
entities: _entities,
|
||||
lastEntityId: const IdUid(1, 1213035855270739890),
|
||||
lastIndexId: const IdUid(1, 8342366639839511243),
|
||||
lastEntityId: const IdUid(2, 8060242331335522964),
|
||||
lastIndexId: const IdUid(2, 6156017341759176249),
|
||||
lastRelationId: const IdUid(0, 0),
|
||||
lastSequenceId: const IdUid(0, 0),
|
||||
retiredEntityUids: const [],
|
||||
|
@ -160,6 +191,40 @@ ModelDefinition getObjectBoxModel() {
|
|||
..dbStatus =
|
||||
const fb.Int64Reader().vTableGet(buffer, rootOffset, 18, 0);
|
||||
|
||||
return object;
|
||||
}),
|
||||
Hashtag: EntityDefinition<Hashtag>(
|
||||
model: _entities[1],
|
||||
toOneRelations: (Hashtag object) => [],
|
||||
toManyRelations: (Hashtag object) => {},
|
||||
getId: (Hashtag object) => object.id,
|
||||
setId: (Hashtag object, int id) {
|
||||
object.id = id;
|
||||
},
|
||||
objectToFB: (Hashtag object, fb.Builder fbb) {
|
||||
final tagOffset = fbb.writeString(object.tag);
|
||||
final urlOffset = fbb.writeString(object.url);
|
||||
fbb.startTable(5);
|
||||
fbb.addInt64(0, object.id);
|
||||
fbb.addOffset(1, tagOffset);
|
||||
fbb.addOffset(2, urlOffset);
|
||||
fbb.addInt64(3, object.lastUpdateTime.millisecondsSinceEpoch);
|
||||
fbb.finish(fbb.endTable());
|
||||
return object.id;
|
||||
},
|
||||
objectFromFB: (Store store, ByteData fbData) {
|
||||
final buffer = fb.BufferContext(fbData);
|
||||
final rootOffset = buffer.derefObject(0);
|
||||
|
||||
final object = Hashtag(
|
||||
id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0),
|
||||
tag: const fb.StringReader(asciiOptimization: true)
|
||||
.vTableGet(buffer, rootOffset, 6, ''),
|
||||
url: const fb.StringReader(asciiOptimization: true)
|
||||
.vTableGet(buffer, rootOffset, 8, ''))
|
||||
..lastUpdateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||
const fb.Int64Reader().vTableGet(buffer, rootOffset, 10, 0));
|
||||
|
||||
return object;
|
||||
})
|
||||
};
|
||||
|
@ -204,3 +269,19 @@ class Connection_ {
|
|||
static final lastUpdateTime =
|
||||
QueryIntegerProperty<Connection>(_entities[0].properties[8]);
|
||||
}
|
||||
|
||||
/// [Hashtag] entity fields to define ObjectBox queries.
|
||||
class Hashtag_ {
|
||||
/// see [Hashtag.id]
|
||||
static final id = QueryIntegerProperty<Hashtag>(_entities[1].properties[0]);
|
||||
|
||||
/// see [Hashtag.tag]
|
||||
static final tag = QueryStringProperty<Hashtag>(_entities[1].properties[1]);
|
||||
|
||||
/// see [Hashtag.url]
|
||||
static final url = QueryStringProperty<Hashtag>(_entities[1].properties[2]);
|
||||
|
||||
/// see [Hashtag.lastUpdateTime]
|
||||
static final lastUpdateTime =
|
||||
QueryIntegerProperty<Hashtag>(_entities[1].properties[3]);
|
||||
}
|
||||
|
|
12
lib/serializers/mastodon/hashtag_mastodon_extensions.dart
Normal file
12
lib/serializers/mastodon/hashtag_mastodon_extensions.dart
Normal file
|
@ -0,0 +1,12 @@
|
|||
import '../../models/hashtag.dart';
|
||||
|
||||
extension HashtagMastodonExtensions on Hashtag {
|
||||
static Hashtag fromJson(Map<String, dynamic> json) {
|
||||
final tag = json['name'];
|
||||
final url = json['url'];
|
||||
return Hashtag(
|
||||
tag: tag,
|
||||
url: url,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import '../../services/connections_manager.dart';
|
|||
import '../../services/hashtag_service.dart';
|
||||
import '../../utils/dateutils.dart';
|
||||
import 'connection_mastodon_extensions.dart';
|
||||
import 'hashtag_mastodon_extensions.dart';
|
||||
|
||||
final _logger = Logger('TimelineEntryMastodonExtensions');
|
||||
|
||||
|
@ -75,9 +76,9 @@ extension TimelineEntryMastodonExtensions on TimelineEntry {
|
|||
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);
|
||||
for (final tagJson in tags!) {
|
||||
final tag = HashtagMastodonExtensions.fromJson(tagJson);
|
||||
tagManager.add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class HashtagService extends ChangeNotifier {
|
||||
final _hashTags = <String>{};
|
||||
import '../data/interfaces/hashtag_repo_intf.dart';
|
||||
import '../globals.dart';
|
||||
import '../models/hashtag.dart';
|
||||
|
||||
void clear() {
|
||||
_hashTags.clear();
|
||||
notifyListeners();
|
||||
class HashtagService extends ChangeNotifier {
|
||||
late final IHashtagRepo repo;
|
||||
|
||||
HashtagService() {
|
||||
repo = getIt<IHashtagRepo>();
|
||||
}
|
||||
|
||||
void addHashtage(String hashtag) {
|
||||
_hashTags.add(hashtag);
|
||||
void add(Hashtag tag) {
|
||||
repo.add(tag);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
List<String> getMatchingHashTags(String searchString) {
|
||||
return _hashTags
|
||||
.where((tag) => tag.toLowerCase().contains(searchString.toLowerCase()))
|
||||
.toList();
|
||||
return repo.getMatchingHashTags(searchString);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue