-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
267 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:camelus/config/default_relays.dart'; | ||
import 'package:camelus/data_layer/models/nostr_note_model.dart'; | ||
|
||
import '../entities/nostr_note.dart'; | ||
import '../entities/nostr_tag.dart'; | ||
import '../repositories/note_repository.dart'; | ||
|
||
class UserReposts { | ||
final NoteRepository _noteRepository; | ||
final String? selfPubkey; | ||
|
||
UserReposts({ | ||
required NoteRepository noteRepository, | ||
this.selfPubkey, | ||
}) : _noteRepository = noteRepository; | ||
|
||
Future<bool> isPostSelfReposted({required String postId}) async { | ||
if (selfPubkey == null) { | ||
return Future.value(false); | ||
} | ||
final res = await isPostRepostedBy( | ||
repostedByPubkey: selfPubkey!, | ||
postId: postId, | ||
); | ||
return res != null; | ||
} | ||
|
||
/// Check if a post is liked by a specific user | ||
/// [returns] the reaction if the post is liked, null otherwise | ||
Future<NostrNote?> isPostRepostedBy({ | ||
required String repostedByPubkey, | ||
required String postId, | ||
}) async { | ||
final reposts = await _noteRepository.getReposts( | ||
postId: postId, | ||
authors: [repostedByPubkey], | ||
); | ||
if (reposts.isEmpty) { | ||
return null; | ||
} | ||
|
||
final res = reposts.where((reaction) { | ||
return reaction.tags.any((tag) => tag.type == "e" && tag.value == postId); | ||
}).first; | ||
|
||
return res; | ||
} | ||
|
||
/// repost a post \ | ||
/// [postToRepost] the post to repost \ | ||
/// | ||
Future<void> repostPost({ | ||
required NostrNote postToRepost, | ||
}) { | ||
if (selfPubkey == null) { | ||
throw Exception("selfPubkey is null"); | ||
} | ||
|
||
final recivedOnRelays = postToRepost.sources; | ||
|
||
final selectedSource = recivedOnRelays.isNotEmpty | ||
? recivedOnRelays.first | ||
: DEFAULT_ACCOUNT_CREATION_RELAYS.keys.last; | ||
|
||
final postToRepostModel = NostrNoteModel( | ||
id: postToRepost.id, | ||
pubkey: postToRepost.pubkey, | ||
created_at: postToRepost.created_at, | ||
kind: postToRepost.kind, | ||
content: postToRepost.content, | ||
sig: postToRepost.sig, | ||
tags: postToRepost.tags, | ||
); | ||
|
||
final now = DateTime.now().millisecondsSinceEpoch ~/ 1000; | ||
final myRepost = NostrNote( | ||
content: jsonEncode(postToRepostModel.toJson()), | ||
pubkey: selfPubkey!, | ||
created_at: now, | ||
kind: 6, | ||
id: "", | ||
sig: "", | ||
tags: [ | ||
NostrTag( | ||
type: "e", | ||
value: postToRepost.id, | ||
recommended_relay: selectedSource, | ||
), | ||
NostrTag(type: "p", value: postToRepost.pubkey), | ||
], | ||
); | ||
return _noteRepository.broadcastNote(myRepost); | ||
} | ||
|
||
/// delete a repost \ | ||
/// [postId] the id of the post to delete the repost from \ | ||
/// [throws] an exception if the repost is not found \ | ||
/// [returns] a future that completes when the repost is deleted | ||
Future<void> deleteRepost({required String postId}) async { | ||
if (selfPubkey == null) { | ||
throw Exception("selfPubkey is null"); | ||
} | ||
|
||
// get the repost to delete | ||
final myRepostEvent = | ||
await isPostRepostedBy(repostedByPubkey: selfPubkey!, postId: postId); | ||
if (myRepostEvent == null) { | ||
throw Exception("Repost event not found"); | ||
} | ||
|
||
return _noteRepository.deleteNote( | ||
myRepostEvent.id, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import 'package:riverpod/riverpod.dart'; | ||
|
||
import '../../data_layer/data_sources/dart_ndk_source.dart'; | ||
import '../../data_layer/repositories/note_repository_impl.dart'; | ||
import '../../domain_layer/repositories/note_repository.dart'; | ||
import '../../domain_layer/usecases/user_reposts.dart'; | ||
import 'event_signer_provider.dart'; | ||
import 'event_verifier.dart'; | ||
import 'ndk_provider.dart'; | ||
|
||
final repostsProvider = Provider<UserReposts>((ref) { | ||
final ndk = ref.watch(ndkProvider); | ||
|
||
final eventVerifier = ref.watch(eventVerifierProvider); | ||
final eventSigner = ref.watch(eventSignerProvider); | ||
|
||
final DartNdkSource dartNdkSource = DartNdkSource(ndk); | ||
|
||
final NoteRepository noteRepository = NoteRepositoryImpl( | ||
dartNdkSource: dartNdkSource, | ||
eventVerifier: eventVerifier, | ||
); | ||
|
||
final UserReposts userReposts = UserReposts( | ||
noteRepository: noteRepository, | ||
selfPubkey: eventSigner?.getPublicKey(), | ||
); | ||
|
||
return userReposts; | ||
}); |
69 changes: 69 additions & 0 deletions
69
lib/presentation_layer/providers/reposts_state_provider.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import 'package:riverpod/riverpod.dart'; | ||
|
||
import '../../domain_layer/entities/nostr_note.dart'; | ||
import '../../domain_layer/usecases/user_reposts.dart'; | ||
import 'reposts_provider.dart'; | ||
|
||
/// class for to save state for each post if it is reposted or not | ||
class PostRepostState { | ||
final bool isReposted; | ||
final bool isLoading; | ||
|
||
PostRepostState({ | ||
required this.isReposted, | ||
required this.isLoading, | ||
}); | ||
|
||
PostRepostState copyWith({bool? isReposted, bool? isLoading}) { | ||
return PostRepostState( | ||
isReposted: isReposted ?? this.isReposted, | ||
isLoading: isLoading ?? this.isLoading, | ||
); | ||
} | ||
} | ||
|
||
final postRepostProvider = StateNotifierProvider.family<PostRepostNotifier, | ||
PostRepostState, NostrNote>( | ||
(ref, arg) { | ||
final userReactions = ref.watch(repostsProvider); | ||
return PostRepostNotifier(userReactions, arg); | ||
}, | ||
); | ||
|
||
class PostRepostNotifier extends StateNotifier<PostRepostState> { | ||
final UserReposts _userReposts; | ||
final NostrNote _displayNote; | ||
|
||
PostRepostNotifier( | ||
this._userReposts, | ||
this._displayNote, | ||
) : super(PostRepostState(isReposted: false, isLoading: true)) { | ||
_initializeRepostState(); | ||
} | ||
|
||
Future<void> _initializeRepostState() async { | ||
final isReposted = | ||
await _userReposts.isPostSelfReposted(postId: _displayNote.id); | ||
|
||
state = state.copyWith(isReposted: isReposted, isLoading: false); | ||
} | ||
|
||
Future<void> toggleRepost() async { | ||
if (state.isLoading) return; | ||
|
||
state = state.copyWith(isLoading: true); | ||
|
||
try { | ||
if (state.isReposted) { | ||
await _userReposts.deleteRepost(postId: _displayNote.id); | ||
} else { | ||
await _userReposts.repostPost(postToRepost: _displayNote); | ||
} | ||
state = state.copyWith(isReposted: !state.isReposted, isLoading: false); | ||
} catch (e) { | ||
print(e); | ||
// Handle error | ||
state = state.copyWith(isLoading: false); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters