Skip to content

Commit

Permalink
main feed new notes
Browse files Browse the repository at this point in the history
  • Loading branch information
leo-lox committed Oct 31, 2024
1 parent 021dc73 commit cb41a5f
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 36 deletions.
7 changes: 7 additions & 0 deletions lib/config/default_relays.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
List<String> CAMELUS_BOOTSTRAP_RELAYS = [
"wss://strfry.iris.to",
"wss://relay.damus.io",
"wss://relay.nostr.band",
"wss://relay.snort.social",
"wss://nos.lol",
];
32 changes: 32 additions & 0 deletions lib/data_layer/repositories/note_repository_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class NoteRepositoryImpl implements NoteRepository {
);
}

/// Get all notes by a list of authors using a query
@override
Stream<NostrNote> getTextNotesByAuthors({
required List<String> authors,
Expand Down Expand Up @@ -91,4 +92,35 @@ class NoteRepositoryImpl implements NoteRepository {
(event) => NostrNoteModel.fromNDKEvent(event),
);
}

/// Get all notes by a list of authors using a subscription
@override
Stream<NostrNote> subscribeTextNotesByAuthors({
required List<String> authors,
required String requestId,
int? since,
int? until,
int? limit,
List<String>? eTags,
}) {
ndk.Filter filter = ndk.Filter(
authors: authors,
kinds: [ndk_entities.Nip01Event.TEXT_NODE_KIND],
since: since,
until: until,
limit: limit,
eTags: eTags,
);

final response = dartNdkSource.dartNdk.requests.subscription(
filters: [filter],
name: requestId,
cacheRead: true,
cacheWrite: true,
);

return response.stream.map(
(event) => NostrNoteModel.fromNDKEvent(event),
);
}
}
9 changes: 9 additions & 0 deletions lib/domain_layer/repositories/note_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,13 @@ abstract class NoteRepository {
int? limit,
List<String>? eTags,
});

Stream<NostrNote> subscribeTextNotesByAuthors({
required List<String> authors,
required String requestId,
int? since,
int? until,
int? limit,
List<String>? eTags,
});
}
15 changes: 13 additions & 2 deletions lib/domain_layer/usecases/main_feed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,17 @@ class MainFeed {
}

final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final newNotesStream = _noteRepository.getTextNotesByAuthors(
final newNotesStream = _noteRepository.subscribeTextNotesByAuthors(
authors: contactList.contacts,
requestId: userFeedFreshId,
since: now,
);

final filterRootNotes = newNotesStream.where((event) => event.isRoot);

filterRootNotes.listen((event) {
_newNotesController.add(event);
});
}

/// load later timelineevents then
Expand Down Expand Up @@ -93,7 +99,12 @@ class MainFeed {
filterRootNotes.listen((event) {
_controller.add(event);
});
}

//_controller.addStream(filterRootNotes);
/// integrate new notes into main feed
void integrateNotes(List<NostrNote> events) {
for (final event in events) {
_controller.add(event);
}
}
}
36 changes: 35 additions & 1 deletion lib/presentation_layer/providers/main_feed_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ final getMainFeedProvider = Provider<MainFeed>((ref) {

final mainFeedStateProvider =
NotifierProvider.family<MainFeedState, List<NostrNote>, String>(
MainFeedState.new);
MainFeedState.new,
);

final mainFeedNewNotesStateProvider =
NotifierProvider.family<MainFeedNewNotesState, List<NostrNote>, String>(
MainFeedNewNotesState.new,
);

// todo: add stateProvider for new events
class MainFeedState extends FamilyNotifier<List<NostrNote>, String> {
Expand Down Expand Up @@ -83,3 +89,31 @@ class MainFeedState extends FamilyNotifier<List<NostrNote>, String> {
state = [];
}
}

class MainFeedNewNotesState extends FamilyNotifier<List<NostrNote>, String> {
@override
List<NostrNote> build(String arg) {
start(arg);
return [];
}

void _addEvents(List<NostrNote> events) {
state = [...state, ...events]
..sort((a, b) => b.created_at.compareTo(a.created_at));
}

start(String pubkey) {
final mainFeedProvider = ref.read(getMainFeedProvider);
final eventStreamBuffer = mainFeedProvider.newNotesStream
.bufferTime(const Duration(
milliseconds: 500,
))
.where((events) => events.isNotEmpty);

eventStreamBuffer.listen((events) {
_addEvents(events);
});

mainFeedProvider.subscribeToFreshNotes(npub: pubkey);
}
}
2 changes: 2 additions & 0 deletions lib/presentation_layer/providers/ndk_provider.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:ndk/ndk.dart';
import 'package:riverpod/riverpod.dart';

import '../../config/default_relays.dart';
import 'db_object_box_provider.dart';
import 'event_signer_provider.dart';
import 'event_verifier.dart';
Expand All @@ -18,6 +19,7 @@ final ndkProvider = Provider<Ndk>((ref) {
cache: dbObjectBox,
eventSigner: eventSigner,
eventVerifier: eventVerifier,
bootstrapRelays: CAMELUS_BOOTSTRAP_RELAYS,
);

final ndk = Ndk(ndkConfig);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:developer';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import 'package:camelus/presentation_layer/atoms/new_posts_available.dart';
import 'package:camelus/presentation_layer/atoms/refresh_indicator_no_need.dart';
Expand Down Expand Up @@ -33,8 +32,6 @@ class _UserFeedOriginalViewState extends ConsumerState<UserFeedOriginalView> {

final Completer<void> _servicesReady = Completer<void>();

bool _newPostsAvailable = false;

// new #########
// final List<NostrNote> timelineEvents = []; // Removed this line
late final Stream<List<NostrNote>> _eventStreamBuffer;
Expand Down Expand Up @@ -75,29 +72,6 @@ class _UserFeedOriginalViewState extends ConsumerState<UserFeedOriginalView> {
widget.scrollControllerFeed.addListener(_scrollListener);
}

void _setupNewNotesListener() {
return;

final mainFeedProvider = ref.read(getMainFeedProvider);

mainFeedProvider.newNotesStream
.bufferTime(const Duration(
seconds: 5,
))
.where((events) => events.isNotEmpty)
.listen((events) {
log("new notes stream event");
if (mounted) {
setState(() {
_newPostsAvailable = true;
});
}

// notify navigation bar
ref.read(navigationBarProvider).newNotesCount = events.length;
});
}

void _setupNavBarHomeListener() {
var provider = ref.read(navigationBarProvider);
_subscriptions.add(provider.onTabHome.listen((event) {
Expand All @@ -106,7 +80,10 @@ class _UserFeedOriginalViewState extends ConsumerState<UserFeedOriginalView> {
}

void _handleHomeBarTab() {
if (_newPostsAvailable) {
final newNotesLenth =
ref.watch(mainFeedNewNotesStateProvider(widget.pubkey)).length;
print("new notes length: $newNotesLenth");
if (newNotesLenth > 0) {
_integrateNewNotes();
return;
}
Expand All @@ -125,17 +102,22 @@ class _UserFeedOriginalViewState extends ConsumerState<UserFeedOriginalView> {
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
setState(() {
_newPostsAvailable = false;
});

final newNotesP = ref.watch(mainFeedNewNotesStateProvider(widget.pubkey));

final notesToIntegrate = newNotesP;
ref.watch(getMainFeedProvider).integrateNotes(notesToIntegrate);

// delte new notes in FeedNew
newNotesP.clear();

ref.watch(navigationBarProvider).resetNewNotesCount();
}

Future<void> _initSequence() async {
if (!mounted) return;

_setupScrollListener();
_setupNewNotesListener();

_setupNavBarHomeListener();

Expand Down Expand Up @@ -167,6 +149,11 @@ class _UserFeedOriginalViewState extends ConsumerState<UserFeedOriginalView> {
@override
Widget build(BuildContext context) {
final timelineEvents = ref.watch(mainFeedStateProvider(widget.pubkey));
final newNotesEvents =
ref.watch(mainFeedNewNotesStateProvider(widget.pubkey));

ref.watch(navigationBarProvider).newNotesCount = newNotesEvents.length;

return FutureBuilder(
future: _servicesReady.future,
builder: (context, snapshot) {
Expand Down Expand Up @@ -205,11 +192,11 @@ class _UserFeedOriginalViewState extends ConsumerState<UserFeedOriginalView> {
},
),
),
if (_newPostsAvailable)
if (newNotesEvents.isNotEmpty)
Container(
margin: const EdgeInsets.only(top: 20),
child: newPostsAvailable(
name: "new posts",
name: "${newNotesEvents.length} new posts",
onPressed: () {
_integrateNewNotes();
}),
Expand Down

0 comments on commit cb41a5f

Please sign in to comment.