diff --git a/lib/models/app.dart b/lib/models/app.dart index fad94bf..1fb4383 100644 --- a/lib/models/app.dart +++ b/lib/models/app.dart @@ -26,9 +26,20 @@ part 'app.g.dart'; @JsonSerializable() @DataAdapter([NostrAdapter, AppAdapter]) class App extends BaseApp with DataModelMixin { - late final HasMany releases; - late final BelongsTo signer; - late final BelongsTo developer; + final HasMany releases; + final BelongsTo signer; + final BelongsTo developer; + + App( + {super.id, + super.pubkey, + super.createdAt, + super.content, + super.tags, + super.signature, + required this.developer, + required this.releases, + required this.signer}); String? get installedVersion => DataModel.adapterFor(this).ref.read(installedAppProvider)[id!.toString()]; @@ -277,11 +288,15 @@ mixin AppAdapter on Adapter { @override DeserializedData deserialize(Object? data, {String? key}) { - // map['signer'] = map['pubkey']; - // final zapTags = (map['tags'] as Iterable).where((t) => t[0] == 'zap'); - // if (zapTags.length == 1) { - // map['developer'] = (zapTags.first as List)[1]; - // } + final list = data is Iterable ? data : [data as Map]; + for (final e in list) { + final map = e as Map; + map['signer'] = map['pubkey']; + final zapTags = (map['tags'] as Iterable).where((t) => t[0] == 'zap'); + if (zapTags.length == 1) { + map['developer'] = (zapTags.first as List)[1]; + } + } return super.deserialize(data); } } diff --git a/lib/models/app.g.dart b/lib/models/app.g.dart index 2909a39..06aef3b 100644 --- a/lib/models/app.g.dart +++ b/lib/models/app.g.dart @@ -87,21 +87,25 @@ extension AppRelationshipGraphNodeX on RelationshipGraphNode { // JsonSerializableGenerator // ************************************************************************** -App _$AppFromJson(Map json) => App() - ..id = json['id'] - ..pubkey = json['pubkey'] as String - ..createdAt = DateTime.parse(json['createdAt'] as String) - ..content = json['content'] as String - ..tags = (json['tags'] as List) - .map((e) => (e as List).map((e) => e as String).toList()) - .toList() - ..signature = json['signature'] as String? - ..kind = (json['kind'] as num).toInt() - ..releases = - HasMany.fromJson(json['releases'] as Map) - ..signer = BelongsTo.fromJson(json['signer'] as Map) - ..developer = - BelongsTo.fromJson(json['developer'] as Map); +App _$AppFromJson(Map json) => App( + id: json['id'], + pubkey: json['pubkey'] as String?, + createdAt: json['createdAt'] == null + ? null + : DateTime.parse(json['createdAt'] as String), + content: json['content'] as String? ?? '', + tags: (json['tags'] as List?) + ?.map( + (e) => (e as List).map((e) => e as String).toList()) + .toList() ?? + const [], + signature: json['signature'] as String?, + developer: + BelongsTo.fromJson(json['developer'] as Map), + releases: + HasMany.fromJson(json['releases'] as Map), + signer: BelongsTo.fromJson(json['signer'] as Map), + ); Map _$AppToJson(App instance) => { 'id': instance.id, @@ -110,7 +114,6 @@ Map _$AppToJson(App instance) => { 'content': instance.content, 'tags': instance.tags, 'signature': instance.signature, - 'kind': instance.kind, 'releases': instance.releases, 'signer': instance.signer, 'developer': instance.developer, diff --git a/lib/models/app_curation_set.dart b/lib/models/app_curation_set.dart index d18663c..7240911 100644 --- a/lib/models/app_curation_set.dart +++ b/lib/models/app_curation_set.dart @@ -10,7 +10,16 @@ part 'app_curation_set.g.dart'; @DataAdapter([NostrAdapter, AppCurationSetAdapter]) class AppCurationSet extends BaseAppCurationSet with DataModelMixin { - late final HasMany apps; + final HasMany apps; + + AppCurationSet( + {super.id, + super.pubkey, + super.createdAt, + super.content, + super.tags, + super.signature, + required this.apps}); } mixin AppCurationSetAdapter on Adapter { diff --git a/lib/models/app_curation_set.g.dart b/lib/models/app_curation_set.g.dart index 92006cd..3d72510 100644 --- a/lib/models/app_curation_set.g.dart +++ b/lib/models/app_curation_set.g.dart @@ -70,17 +70,21 @@ extension AppCurationSetRelationshipGraphNodeX // ************************************************************************** AppCurationSet _$AppCurationSetFromJson(Map json) => - AppCurationSet() - ..id = json['id'] - ..pubkey = json['pubkey'] as String - ..createdAt = DateTime.parse(json['createdAt'] as String) - ..content = json['content'] as String - ..kind = (json['kind'] as num).toInt() - ..tags = (json['tags'] as List) - .map((e) => (e as List).map((e) => e as String).toList()) - .toList() - ..signature = json['signature'] as String? - ..apps = HasMany.fromJson(json['apps'] as Map); + AppCurationSet( + id: json['id'], + pubkey: json['pubkey'] as String?, + createdAt: json['createdAt'] == null + ? null + : DateTime.parse(json['createdAt'] as String), + content: json['content'] as String? ?? '', + tags: (json['tags'] as List?) + ?.map( + (e) => (e as List).map((e) => e as String).toList()) + .toList() ?? + const [], + signature: json['signature'] as String?, + apps: HasMany.fromJson(json['apps'] as Map), + ); Map _$AppCurationSetToJson(AppCurationSet instance) => { @@ -88,7 +92,6 @@ Map _$AppCurationSetToJson(AppCurationSet instance) => 'pubkey': instance.pubkey, 'createdAt': instance.createdAt.toIso8601String(), 'content': instance.content, - 'kind': instance.kind, 'tags': instance.tags, 'signature': instance.signature, 'apps': instance.apps, diff --git a/lib/models/file_metadata.dart b/lib/models/file_metadata.dart index da479f1..6e43ca4 100644 --- a/lib/models/file_metadata.dart +++ b/lib/models/file_metadata.dart @@ -10,9 +10,20 @@ part 'file_metadata.g.dart'; @JsonSerializable() @DataAdapter([NostrAdapter, FileMetadataAdapter]) class FileMetadata extends BaseFileMetadata with DataModelMixin { - late final BelongsTo author; - late final BelongsTo release = BelongsTo(); - late final BelongsTo signer; + final BelongsTo author; + final BelongsTo release; + final BelongsTo signer; + + FileMetadata( + {super.id, + super.pubkey, + super.createdAt, + super.content, + super.tags, + super.signature, + required this.author, + required this.release, + required this.signer}); } mixin FileMetadataAdapter on Adapter { diff --git a/lib/models/file_metadata.g.dart b/lib/models/file_metadata.g.dart index 42f6353..0701934 100644 --- a/lib/models/file_metadata.g.dart +++ b/lib/models/file_metadata.g.dart @@ -91,18 +91,24 @@ extension FileMetadataRelationshipGraphNodeX // JsonSerializableGenerator // ************************************************************************** -FileMetadata _$FileMetadataFromJson(Map json) => FileMetadata() - ..id = json['id'] - ..pubkey = json['pubkey'] as String - ..createdAt = DateTime.parse(json['createdAt'] as String) - ..content = json['content'] as String - ..kind = (json['kind'] as num).toInt() - ..tags = (json['tags'] as List) - .map((e) => (e as List).map((e) => e as String).toList()) - .toList() - ..signature = json['signature'] as String? - ..author = BelongsTo.fromJson(json['author'] as Map) - ..signer = BelongsTo.fromJson(json['signer'] as Map); +FileMetadata _$FileMetadataFromJson(Map json) => FileMetadata( + id: json['id'], + pubkey: json['pubkey'] as String?, + createdAt: json['createdAt'] == null + ? null + : DateTime.parse(json['createdAt'] as String), + content: json['content'] as String? ?? '', + tags: (json['tags'] as List?) + ?.map( + (e) => (e as List).map((e) => e as String).toList()) + .toList() ?? + const [], + signature: json['signature'] as String?, + author: BelongsTo.fromJson(json['author'] as Map), + release: + BelongsTo.fromJson(json['release'] as Map), + signer: BelongsTo.fromJson(json['signer'] as Map), + ); Map _$FileMetadataToJson(FileMetadata instance) => { @@ -110,9 +116,9 @@ Map _$FileMetadataToJson(FileMetadata instance) => 'pubkey': instance.pubkey, 'createdAt': instance.createdAt.toIso8601String(), 'content': instance.content, - 'kind': instance.kind, 'tags': instance.tags, 'signature': instance.signature, 'author': instance.author, + 'release': instance.release, 'signer': instance.signer, }; diff --git a/lib/models/nostr_adapter.dart b/lib/models/nostr_adapter.dart index 7f75fd4..eb549ce 100644 --- a/lib/models/nostr_adapter.dart +++ b/lib/models/nostr_adapter.dart @@ -5,15 +5,9 @@ mixin NostrAdapter> on Adapter { late final RelayMessageNotifier notifier = ref.read(relayMessageNotifierProvider.notifier); - // TODO rethink this - Map kindType = { - 0: 'users', - 3: 'users', - 1063: 'fileMetadata', - 30063: 'releases', - 30267: 'appCurationSets', - 32267: 'apps' - }; + int get kind { + return BaseEvent.kindForType(internalType)!; + } @override DeserializedData deserialize(Object? data, {String? key}) { @@ -23,40 +17,32 @@ mixin NostrAdapter> on Adapter { for (final e in list) { final map = e as Map; + + // Convert nostr-specific timestamp into a DateTime map['createdAt'] = DateTime.fromMillisecondsSinceEpoch(map['created_at'] * 1000) .toIso8601String(); final kind = map['kind'] as int; + // ID should be the identifier in PREs final dTags = (map['tags'] as Iterable).where((t) => t[0] == 'd'); if (dTags.length == 1) { map['id'] = (dTags.first as List)[1]; } - // TODO remove - map['signer'] = map['pubkey']; - final zapTags = (map['tags'] as Iterable).where((t) => t[0] == 'zap'); - if (zapTags.length == 1) { - map['developer'] = (zapTags.first as List)[1]; - } - final xType = kindType[kind]; - if (xType != null) { - if (xType == internalType) { - final newData = super.deserialize(map); - models.addAll(newData.models as Iterable); - } else { - final newData = adapters[xType]!.deserialize(map); - included.addAll(newData.models as Iterable); - } + // Collect models for current kind and included for others + final eventType = BaseEvent.kinds[kind]!; + if (eventType == internalType) { + final newData = super.deserialize(map); + models.addAll(newData.models as Iterable); + } else { + final newData = adapters[eventType]!.deserialize(map); + included.addAll(newData.models as Iterable); } } return DeserializedData(models, included: included); } - // TODO remove - int get kind => - kindType.entries.firstWhere((e) => e.value == internalType).key; - @override Future> findAll( {bool? remote, diff --git a/lib/models/release.dart b/lib/models/release.dart index e59cf9d..81886ba 100644 --- a/lib/models/release.dart +++ b/lib/models/release.dart @@ -12,9 +12,20 @@ part 'release.g.dart'; @JsonSerializable() @DataAdapter([NostrAdapter, ReleaseAdapter]) class Release extends BaseRelease with DataModelMixin { - late final HasMany artifacts; - late final BelongsTo app; - late final BelongsTo signer; + final HasMany artifacts; + final BelongsTo app; + final BelongsTo signer; + + Release( + {super.id, + super.pubkey, + super.createdAt, + super.content, + super.tags, + super.signature, + required this.artifacts, + required this.app, + required this.signer}); } mixin ReleaseAdapter on Adapter { diff --git a/lib/models/release.g.dart b/lib/models/release.g.dart index 70a3766..f163855 100644 --- a/lib/models/release.g.dart +++ b/lib/models/release.g.dart @@ -89,27 +89,30 @@ extension ReleaseRelationshipGraphNodeX on RelationshipGraphNode { // JsonSerializableGenerator // ************************************************************************** -Release _$ReleaseFromJson(Map json) => Release() - ..id = json['id'] - ..pubkey = json['pubkey'] as String - ..createdAt = DateTime.parse(json['createdAt'] as String) - ..content = json['content'] as String - ..kind = (json['kind'] as num).toInt() - ..tags = (json['tags'] as List) - .map((e) => (e as List).map((e) => e as String).toList()) - .toList() - ..signature = json['signature'] as String? - ..artifacts = - HasMany.fromJson(json['artifacts'] as Map) - ..app = BelongsTo.fromJson(json['app'] as Map) - ..signer = BelongsTo.fromJson(json['signer'] as Map); +Release _$ReleaseFromJson(Map json) => Release( + id: json['id'], + pubkey: json['pubkey'] as String?, + createdAt: json['createdAt'] == null + ? null + : DateTime.parse(json['createdAt'] as String), + content: json['content'] as String? ?? '', + tags: (json['tags'] as List?) + ?.map( + (e) => (e as List).map((e) => e as String).toList()) + .toList() ?? + const [], + signature: json['signature'] as String?, + artifacts: HasMany.fromJson( + json['artifacts'] as Map), + app: BelongsTo.fromJson(json['app'] as Map), + signer: BelongsTo.fromJson(json['signer'] as Map), + ); Map _$ReleaseToJson(Release instance) => { 'id': instance.id, 'pubkey': instance.pubkey, 'createdAt': instance.createdAt.toIso8601String(), 'content': instance.content, - 'kind': instance.kind, 'tags': instance.tags, 'signature': instance.signature, 'artifacts': instance.artifacts, diff --git a/lib/models/user.dart b/lib/models/user.dart index 7aac0af..bee2517 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -11,10 +11,20 @@ part 'user.g.dart'; @JsonSerializable() @DataAdapter([NostrAdapter, UserAdapter]) class User extends BaseUser with DataModelMixin { + User( + {super.id, + super.pubkey, + super.createdAt, + super.content, + super.tags, + super.signature, + required this.followers, + required this.following}); + @DataRelationship(inverse: 'followers') - late final HasMany following; + final HasMany following; @DataRelationship(inverse: 'following') - late final HasMany followers = HasMany(); + final HasMany followers; String get nameOrNpub => name ?? '${npub.substring(0, 10)}...'; } diff --git a/lib/models/user.g.dart b/lib/models/user.g.dart index 631752e..b569788 100644 --- a/lib/models/user.g.dart +++ b/lib/models/user.g.dart @@ -76,26 +76,32 @@ extension UserRelationshipGraphNodeX on RelationshipGraphNode { // JsonSerializableGenerator // ************************************************************************** -User _$UserFromJson(Map json) => User() - ..id = json['id'] - ..pubkey = json['pubkey'] as String - ..createdAt = DateTime.parse(json['createdAt'] as String) - ..content = json['content'] as String - ..kind = (json['kind'] as num).toInt() - ..tags = (json['tags'] as List) - .map((e) => (e as List).map((e) => e as String).toList()) - .toList() - ..signature = json['signature'] as String? - ..following = - HasMany.fromJson(json['following'] as Map); +User _$UserFromJson(Map json) => User( + id: json['id'], + pubkey: json['pubkey'] as String?, + createdAt: json['createdAt'] == null + ? null + : DateTime.parse(json['createdAt'] as String), + content: json['content'] as String? ?? '', + tags: (json['tags'] as List?) + ?.map( + (e) => (e as List).map((e) => e as String).toList()) + .toList() ?? + const [], + signature: json['signature'] as String?, + followers: + HasMany.fromJson(json['followers'] as Map), + following: + HasMany.fromJson(json['following'] as Map), + ); Map _$UserToJson(User instance) => { 'id': instance.id, 'pubkey': instance.pubkey, 'createdAt': instance.createdAt.toIso8601String(), 'content': instance.content, - 'kind': instance.kind, 'tags': instance.tags, 'signature': instance.signature, 'following': instance.following, + 'followers': instance.followers, }; diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 9f712f9..9ef8b10 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -56,7 +56,7 @@ class SettingsScreen extends HookConsumerWidget { onPressed: () async { final text = '${controller.text.trim()} [from ${user.npub} on ${DateFormat('MMMM d, y').format(DateTime.now())}]'; - final event = BaseEvent.partial(content: text).sign(kI); + final event = BaseEvent(content: text).sign(kI); await ref.apps.nostrAdapter.notifier .publish(event, relayUrls: ['wss://relay.zap.store']); controller.clear(); diff --git a/pubspec.lock b/pubspec.lock index 8c90a9c..c9591ae 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -257,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.6" + decimal: + dependency: transitive + description: + name: decimal + sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21" + url: "https://pub.dev" + source: hosted + version: "2.3.3" device_apps: dependency: "direct main" description: @@ -508,6 +516,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + humanizer: + dependency: transitive + description: + name: humanizer + sha256: "08728a4b6d62accd7d09e668bd54e81e6e09a82c8cfda30553224b3eb868d4f2" + url: "https://pub.dev" + source: hosted + version: "2.2.0" image: dependency: transitive description: @@ -851,6 +867,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" + rational: + dependency: transitive + description: + name: rational + sha256: ba58e9e18df9abde280e8b10051e4bce85091e41e8e7e411b6cde2e738d357cf + url: "https://pub.dev" + source: hosted + version: "2.2.2" riverpod: dependency: transitive description: