From dd9e9a3c0298f1cde5d1e2a68644dfe7d751f055 Mon Sep 17 00:00:00 2001 From: Vishal <64505169+vishalxl@users.noreply.github.com> Date: Thu, 29 Dec 2022 02:20:58 +0530 Subject: [PATCH] changed display filters and saving logic displyed global feed. and in incoming notifications, only showed notifications for follows. In writing events, only writing follow's events. and the ones they interact with. now all follows have a tick; no tick for defaults --- lib/console_ui.dart | 26 +++++------ lib/event_ds.dart | 28 +++++++----- lib/settings.dart | 2 +- lib/tree_ds.dart | 102 ++++++++++++++++++++++++++++++++------------ lib/user.dart | 23 +++------- pubspec.yaml | 13 ++++-- 6 files changed, 120 insertions(+), 74 deletions(-) diff --git a/lib/console_ui.dart b/lib/console_ui.dart index 42bd09a..a5c43bf 100644 --- a/lib/console_ui.dart +++ b/lib/console_ui.dart @@ -30,6 +30,7 @@ Future processAnyIncomingEvents(Store node, [bool printNotifications = tru List numPrinted1 = [0,0,0]; if( printNotifications) { + // print all the new trees, the ones that we want to print numPrinted1 = node.printTreeNotifications(newEventIds); // need to clear because only top 20 events in each thread are printed or cleared with above @@ -303,7 +304,7 @@ void printProfile(Store node, String profilePubkey) { node.printStoreTrees(0, DateTime.now().subtract(Duration(hours:gHoursDefaultPrint)), onlyUserPostAndLike); // if contact list was found, get user's feed, and keep the contact list for later use - String authorName = getAuthorName(profilePubkey, addTickForWellKnown: false ); + String authorName = getAuthorName(profilePubkey); String pronoun = ""; if( profilePubkey == userPublicKey) { printUnderlined("\nYour profile - $authorName:"); @@ -1280,9 +1281,9 @@ Future socialMenuUi(Store node) async { // the main menu int option = showMenu([ - 'All Posts', // 1 + 'Your Feed', // 1 'Post/Reply/Like', // 2 - 'Your notifications',// 3 + 'Replies/Likes to you',// 3 'Your Posts', // 4 'Your Replies/Likes',//5 'Follows\' Posts/Replies/Likes', // 6 @@ -1295,7 +1296,8 @@ Future socialMenuUi(Store node) async { switch(option) { case 1: - node.printStoreTrees(0, DateTime.now().subtract(Duration(hours:gHoursDefaultPrint)), selectorTrees_all); + bool selectorTrees_followActionsNoNotifications (Tree t) => t.treeSelectorUserPostAndLike(getFollows( userPublicKey), enableNotifications: false); + node.printStoreTrees(0, DateTime.now().subtract(Duration(hours:gHoursDefaultPrint)), selectorTrees_followActionsNoNotifications); await processAnyIncomingEvents(node, true); break; @@ -1341,9 +1343,9 @@ Future socialMenuUi(Store node) async { int notificationHours = gHoursDefaultPrint>24? gHoursDefaultPrint: 24; // minimum 24 List numPrinted = node.printStoreTrees(0, DateTime.now().subtract(Duration(hours:notificationHours)), selectorTrees_userNotifications); if( numPrinted[2] > 0) { - print("Showed ${numPrinted[2]} notifications.\n"); + print("Showed ${numPrinted[2]} replies/likes that were made to your posts.\n"); } else { - print("No notifications."); + print("No replies or likes."); } await processAnyIncomingEvents(node, true); @@ -1351,8 +1353,8 @@ Future socialMenuUi(Store node) async { case 4: clearScreen(); List numPrinted = node.printStoreTrees(0, DateTime.now().subtract(Duration(hours:gHoursDefaultPrint)), selectorTrees_selfPosts); - if( numPrinted[2] > 0) { - print("Showed ${numPrinted[2]} posts made by you in last $gHoursDefaultPrint hours.\n"); + if( numPrinted[0] > 0) { + print("Showed ${numPrinted[0]} posts made by you in last $gHoursDefaultPrint hours.\n"); } else { print("No posts made by you in last $gHoursDefaultPrint hours."); } @@ -1373,8 +1375,8 @@ Future socialMenuUi(Store node) async { case 6: clearScreen(); - bool selectorTrees_followActions (Tree t) => t.treeSelectorUserPostAndLike(getFollows( userPublicKey)); - List numPrinted = node.printStoreTrees(0, DateTime.now().subtract(Duration(hours:gHoursDefaultPrint)), selectorTrees_followActions); + bool selectorTrees_followActionsWithNotifications (Tree t) => t.treeSelectorUserPostAndLike(getFollows( userPublicKey), enableNotifications: true); + List numPrinted = node.printStoreTrees(0, DateTime.now().subtract(Duration(hours:gHoursDefaultPrint)), selectorTrees_followActionsWithNotifications); if( numPrinted[0] > 0) { print("Showed ${numPrinted[0]} threads where your follows participated.\n"); } else { @@ -1580,8 +1582,8 @@ Future mainMenuUi(Store node) async { firstTime = false; // the main menu - int option = showMenu(['Home Page', // 1 - 'Social Network', // 2 + int option = showMenu(['Global Feed', // 1 + 'Social Network', // 2 'Public Channels', // 3 'Encrypted Channels',// 4 'Private Messages', // 5 diff --git a/lib/event_ds.dart b/lib/event_ds.dart index 5eef2c7..b4d2f18 100644 --- a/lib/event_ds.dart +++ b/lib/event_ds.dart @@ -4,6 +4,7 @@ import 'dart:math'; import 'package:bip340/bip340.dart'; import 'package:intl/intl.dart'; import 'package:nostr_console/tree_ds.dart'; +import 'package:nostr_console/user.dart'; import 'package:nostr_console/utils.dart'; import 'package:translator/translator.dart'; import 'package:crypto/crypto.dart'; @@ -1246,7 +1247,12 @@ String getNip05Name( String pubkey) { } // returns name by looking up global list gKindONames, which is populated by kind 0 events -String getAuthorName(String pubkey, {bool addTickForWellKnown = true, int maxDisplayLen = gMaxInteger, int pubkeyLenShown = 5}) { +String getAuthorName(String pubkey, {int maxDisplayLen = gMaxInteger, int pubkeyLenShown = 5}) { + + if( gFollowList.length == 0) { + gFollowList = getFollows(userPublicKey); + } + bool isFollow = gFollowList.contains(pubkey) && (pubkey != userPublicKey); String maxLen(String pubkey) => pubkey.length > pubkeyLenShown? pubkey.substring(0,pubkeyLenShown) : pubkey.substring(0, pubkey.length); String name = ""; @@ -1256,19 +1262,19 @@ String getAuthorName(String pubkey, {bool addTickForWellKnown = true, int maxDis name = (gKindONames[pubkey]?.name)??maxLen(pubkey); } - if( addTickForWellKnown) { - // first remove the check mark if its in any name + // then add valid check mark in default follows + if( isFollow) { + if( name.length >= maxDisplayLen ) { + name = name.substring(0, maxDisplayLen-1) + gValidCheckMark; + } else { + name = name + gValidCheckMark; + } + } else { + // make this tick a specil character name = name.replaceAll(gValidCheckMark, ""); - // then add valid check mark in default follows - if( gDefaultFollows.contains(pubkey)) { - if( name.length >= maxDisplayLen ) { - name = name.substring(0, maxDisplayLen-1) + gValidCheckMark; - } else { - name = name + gValidCheckMark; - } - } } + return name; } diff --git a/lib/settings.dart b/lib/settings.dart index b211d8d..43d0a6d 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -3,7 +3,7 @@ import 'package:logging/logging.dart'; // name of executable const String exename = "nostr_console"; -const String version = "0.3.1-beta-b"; +const String version = "0.3.2-beta"; int gDebug = 0; int gSpecificDebug = 0; diff --git a/lib/tree_ds.dart b/lib/tree_ds.dart index c7a13e6..6a5dc97 100644 --- a/lib/tree_ds.dart +++ b/lib/tree_ds.dart @@ -559,8 +559,39 @@ class Tree { return false; } - // returns true if the tree or its children has a post or like by user; and notification flags are set for such events - bool treeSelectorUserPostAndLike(Set pubkeys) { + // returns true if the tree has a reply by any of the pubkeys sent + // only used by writefile + bool treeSelectorUserPosted(Set pubkeys, [bool checkChildrenToo = false]) { + + if( pubkeys.contains(event.eventData.pubkey)) { + return true; + } + + for( int i = 0; i < children.length; i++ ) { + if( children[i].treeSelectorUserPosted(pubkeys)) { + return true; + } + } + + return false; + } + + // returns true if the tree has a reply by any of the pubkeys sent + // only used by writefile + bool treeSelectorUserReplies(Set pubkeys) { + + for( int i = 0; i < children.length; i++ ) { + if( children[i].treeSelectorUserPosted(pubkeys)) { + return true; + } + } + + return false; + } + + + // returns true if the tree (or its children, depending on flag) has a post or like by user; and notification flags are set for such events + bool treeSelectorUserPostAndLike(Set pubkeys, { bool enableNotifications = true, bool checkChildrenToo = true}) { bool hasReacted = false; if( gReactions.containsKey(event.eventData.id)) { @@ -568,7 +599,8 @@ class Tree { if( reactions != null) { for( int i = 0; i < reactions.length; i++) { if( pubkeys.contains(reactions[i][0]) ) { - event.eventData.newLikes.add(reactions[i][0]); + if( enableNotifications) + event.eventData.newLikes.add(reactions[i][0]); hasReacted = true; } } @@ -576,15 +608,19 @@ class Tree { } bool childMatches = false; - for( int i = 0; i < children.length; i++ ) { - if( children[i].treeSelectorUserPostAndLike(pubkeys)) { - childMatches = true; + + if( checkChildrenToo ) { + for( int i = 0; i < children.length; i++ ) { + if( children[i].treeSelectorUserPostAndLike(pubkeys)) { + childMatches = true; + } } } // if event is by user(s) if( pubkeys.contains(event.eventData.pubkey)) { - event.eventData.isNotification = true; + if( enableNotifications) + event.eventData.isNotification = true; return true; } if( hasReacted || childMatches) { @@ -1605,13 +1641,19 @@ class Store { Store.reCalculateMarkerStr(); + // update this list, because it is internally used by printEvent + gFollowList = getFollows(userPublicKey); + List ret = [0,0,0]; - topNotificationTree.forEach( (t) { - List temp = Store.printTopPost(t, 0, DateTime(0)); - ret[0] += temp[0]; - ret[1] += temp[1]; - ret[2] += temp[2]; - print("\n"); + topNotificationTree.forEach( (t) { + bool selectorTrees_followActionsWithNotifications (Tree t) => t.treeSelectorUserPostAndLike(getFollows( userPublicKey), enableNotifications: true); + if( selectorTrees_followActionsWithNotifications(t)) { + List temp = Store.printTopPost(t, 0, DateTime(0)); + ret[0] += temp[0]; + ret[1] += temp[1]; + ret[2] += temp[2]; + print("\n"); + } }); return ret; @@ -1642,6 +1684,9 @@ class Store { */ List printStoreTrees(int depth, DateTime newerThan, fTreeSelector treeSelector, [int maxToPrint = gMaxEventsInThreadPrinted]) { + // update this list, because it is internally used by printEvent + gFollowList = getFollows(userPublicKey); + topPosts.sort(sortTreeNewestReply); // sorting done only for top most threads. Lower threads aren't sorted so save cpu etc TODO improve top sorting // https://gist.github.com/dsample/79a97f38bf956f37a0f99ace9df367b9 @@ -2046,18 +2091,26 @@ class Store { return room; } - - // TODO to be finished + // threads where the user and follows have involved themselves are returnes as true ( relevant) bool isRelevant(Tree tree) { - //Set contacts = getContactList(userPublicKey); - //contacts = contacts.union(gDefaultFollows); + if( tree.treeSelectorUserPostAndLike(gFollowList) + || tree.treeSelectorUserPostAndLike({userPublicKey}) + || tree.treeSelectorUserReplies(gFollowList)) { + return true; + } - return true; + return false; } // Write the tree's events to file as one event's json per line Future writeEventsToFile(String filename) async { + + // this variable will be used later; update it if needed + if( gFollowList.length == 0) { + gFollowList = getFollows(userPublicKey); + } + if( gDebug > 0) print("opening $filename to write to."); try { final File file = File(filename); @@ -2075,7 +2128,9 @@ class Store { int linesWritten = 0; for( var tree in allChildEventsMap.values) { - if( tree.event.eventData.isDeleted) { // dont write those deleted + if( tree.event.eventData.isDeleted // dont write those deleted + || gDummyAccountPubkey == tree.event.eventData.pubkey // dont write dummy events + || tree.event.originalJson.length < 10) { continue; } @@ -2085,18 +2140,9 @@ class Store { } } - if( gDummyAccountPubkey == tree.event.eventData.pubkey) { - continue; // dont write dummy events - } - - if( tree.event.originalJson.length < 10) { - continue; - } - if( !isRelevant(tree)) { continue; } - String temp = tree.event.originalJson.trim(); String line = "${temp}\n"; diff --git a/lib/user.dart b/lib/user.dart index 80e9e84..b8e048e 100644 --- a/lib/user.dart +++ b/lib/user.dart @@ -3,6 +3,10 @@ import 'package:nostr_console/event_ds.dart'; import 'package:nostr_console/settings.dart'; import 'package:nostr_console/utils.dart'; + +// is set intermittently by functions. and used as required. Should be kept in sync as the kind 3 for user are received. +Set gFollowList = {}; + // From the list of events provided, lookup the lastst contact information for the given user/pubkey Event? getContactEvent(String pubkey) { @@ -28,6 +32,7 @@ Set getFollows(String pubkey) { return followPubkeys; } + Set getUserChannels(Set userEvents, String userPublicKey) { Set userChannels = {}; @@ -94,21 +99,3 @@ Set getOnlyUserEvents(Set initialEvents, String userPubkey) { return userEvents; } - -Set getContactList(String pubkey) { - Set contacts = {}; - - if( pubkey != "") { - // get the latest kind 3 event for the user, which has the 'follows' list - Event? contactEvent = getContactEvent(userPublicKey); - - // if contact list was found, get user's feed; also get some default contacts - if (contactEvent != null ) { - contactEvent.eventData.contactList.forEach((contact) { - contacts.add(contact.contactPubkey); - }); - } else { - } - } - return contacts; -} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 74da5e9..8b3bddc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,17 @@ name: nostr_console description: A multi-platform nostr client built for terminal/console -version: 0.3.1-beta-b +version: 0.3.2-beta homepage: https://github.com/vishalxl/nostr_console - + +# 0.3.2 # added build for ubuntu arm 64, and mac arm 64 -# matrix change , removed old build entries in dart.yml files -# one off build with num channel messages = 40 +# fixed or improved mention expansion +# displyed global feed. which has all latest in last 2 hours +# in incoming notifications, only showed notifications for follows. +# In writing events, only writing follow's events. and the ones they interact with. +# now friends have a tick; no tick for defaults +# fixed likes colors issue for notification likes # 0.3.1 # added nostr.ch as another default relay to sync with anigma