mirror of
https://github.com/vishalxl/nostr_console.git
synced 2025-03-17 21:31:52 +01:00
added analysis_options.yaml and ran lint and applied changes
This commit is contained in:
parent
626a2f66c5
commit
b9ac5538b3
26
analysis_options.yaml
Normal file
26
analysis_options.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
# reference : https://dart.dev/tools/analysis
|
||||
|
||||
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
analyzer:
|
||||
exclude: [build/**]
|
||||
language:
|
||||
strict-raw-types: true
|
||||
strict-inference: true
|
||||
|
||||
# not including
|
||||
# strict-casts: true
|
||||
|
||||
|
||||
linter:
|
||||
rules:
|
||||
- use_super_parameters
|
||||
- cancel_subscriptions
|
||||
- close_sinks
|
||||
- combinators_ordering
|
||||
- comment_references
|
||||
- invalid_case_patterns
|
||||
- library_annotations
|
||||
- one_member_abstracts
|
||||
- only_throw_errors
|
@ -92,7 +92,7 @@ Future<void> main(List<String> arguments) async {
|
||||
userPrivateKey = "";
|
||||
}
|
||||
|
||||
if( gUserLocation.length > 0){
|
||||
if( gUserLocation.isNotEmpty){
|
||||
print("Going to add $gUserLocation as the location tag with each post.");
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ Future<void> main(List<String> arguments) async {
|
||||
|
||||
// write informative message in case user is not using proper keys
|
||||
if( userPublicKey == gDefaultPublicKey) {
|
||||
print("You should ideally create your own private key and use it with ${gWarningColor}--prikey$gColorEndMarker program argument. ");
|
||||
print("You should ideally create your own private key and use it with $gWarningColor--prikey$gColorEndMarker program argument. ");
|
||||
print("Create a private key from ${gWarningColor}astral.ninja, @damusapp, or even from command line using `openssl rand -hex 32`.$gColorEndMarker.\n");
|
||||
print("npub/nsec keys can be converted to hex key format using https://damus.io/key");
|
||||
}
|
||||
@ -127,16 +127,16 @@ Future<void> main(List<String> arguments) async {
|
||||
if( argResults[relayArg] != null) {
|
||||
Set<String> userRelayList = Set.from(argResults[relayArg].split(","));
|
||||
Set<String> parsedRelays = {};
|
||||
userRelayList.forEach((relay) {
|
||||
for (var relay in userRelayList) {
|
||||
if(relay.startsWith(RegExp(r'^ws[s]?:\/\/'))) {
|
||||
parsedRelays.add(relay);
|
||||
} else {
|
||||
printWarning("The provided relay entry: \"$relay\" does not start with ws:// or wss://, omitting");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// verify that there is at least one valid relay they provided, otherwise keep defaults
|
||||
if (parsedRelays.length > 0) {
|
||||
if (parsedRelays.isNotEmpty) {
|
||||
gListRelayUrls = parsedRelays;
|
||||
defaultServerUrl = gListRelayUrls.first;
|
||||
} else {
|
||||
@ -174,8 +174,9 @@ Future<void> main(List<String> arguments) async {
|
||||
|
||||
try {
|
||||
var terminalColumns = gDefaultTextWidth;
|
||||
if( stdout.hasTerminal )
|
||||
if( stdout.hasTerminal ) {
|
||||
terminalColumns = stdout.terminalColumns;
|
||||
}
|
||||
|
||||
// can be computed only after textWidth has been found
|
||||
if( gTextWidth > terminalColumns) {
|
||||
@ -184,7 +185,7 @@ Future<void> main(List<String> arguments) async {
|
||||
gNumLeftMarginSpaces = (terminalColumns - gTextWidth )~/2;
|
||||
} on StdoutException catch (e) {
|
||||
print("Cannot find terminal size. Left aligning by default.");
|
||||
if( gDebug > 0) log.info("${e.message}");
|
||||
if( gDebug > 0) log.info(e.message);
|
||||
gNumLeftMarginSpaces = 0;
|
||||
}
|
||||
// undo above if left option is given
|
||||
@ -262,10 +263,10 @@ Future<void> main(List<String> arguments) async {
|
||||
stdout.write('Reading events from ${whetherDefault}file.......');
|
||||
|
||||
// read file events and give the events to relays from where they're picked up later
|
||||
initialEvents = await readEventsFromFile(gEventsFilename);
|
||||
initialEvents = readEventsFromFile(gEventsFilename);
|
||||
|
||||
// count events
|
||||
initialEvents.forEach((element) { numFileEvents++;});
|
||||
for (var element in initialEvents) { numFileEvents++;}
|
||||
print("read $numFileEvents events from file $gEventsFilename");
|
||||
}
|
||||
|
||||
@ -338,7 +339,7 @@ Future<void> main(List<String> arguments) async {
|
||||
clearEvents();
|
||||
|
||||
|
||||
initialEvents.forEach((element) { element.eventData.kind == 1? numUserPosts++: numUserPosts;});
|
||||
for (var element in initialEvents) { element.eventData.kind == 1? numUserPosts++: numUserPosts;}
|
||||
numUserPosts -= numFilePosts;
|
||||
stdout.write("...done\n");//received $numUserPosts new posts made by the user\n");
|
||||
|
||||
@ -353,7 +354,9 @@ Future<void> main(List<String> arguments) async {
|
||||
getKindEvents([40, 41], gListRelayUrls, limitPerSubscription, getSecondsDaysAgo(limitSelfEvents));
|
||||
getKindEvents([42], gListRelayUrls, 3 * limitPerSubscription, getSecondsDaysAgo(limitOthersEvents));
|
||||
|
||||
initialEvents.forEach((e) => processKind3Event(e)); // first process the kind 3 event ; basically populate the global structure that holds this info
|
||||
for (var e in initialEvents) {
|
||||
processKind3Event(e);
|
||||
} // first process the kind 3 event ; basically populate the global structure that holds this info
|
||||
|
||||
Set<String> contacts = {};
|
||||
Set<String> pTags = {};
|
||||
@ -365,9 +368,9 @@ Future<void> main(List<String> arguments) async {
|
||||
// if contact list was found, get user's feed; also get some default contacts
|
||||
if (contactEvent != null ) {
|
||||
if(gDebug > 0) print("In main: found contact list: \n ${contactEvent.originalJson}");
|
||||
contactEvent.eventData.contactList.forEach((contact) {
|
||||
for (var contact in contactEvent.eventData.contactList) {
|
||||
contacts.add(contact.contactPubkey);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
print("Could not find your contact list.");
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ Future<void> sendReplyPostLike(Store node, String replyToId, String replyKind, S
|
||||
|
||||
int numShaDone = 0;
|
||||
for( numShaDone = 0; numShaDone < 100000000; numShaDone++) {
|
||||
vanityTag = strTags + ',["nonce","$numShaDone","$gDifficulty"]';
|
||||
vanityTag = '$strTags,["nonce","$numShaDone","$gDifficulty"]';
|
||||
id = getShaId(userPublicKey, createdAt.toString(), replyKind, vanityTag, content);
|
||||
if( id.substring(0, numBytes) == zeroString) {
|
||||
break;
|
||||
@ -160,7 +160,7 @@ Future<void> sendChannelReply(Store node, Channel channel, String replyTo, Strin
|
||||
// send DM
|
||||
Future<void> sendDirectMessage(Store node, String otherPubkey, String messageToSend, {String replyKind = "4"}) async {
|
||||
//messageToSend = addEscapeChars(messageToSend); since this get encrypted , it does not need escaping
|
||||
String otherPubkey02 = "02" + otherPubkey;
|
||||
String otherPubkey02 = "02$otherPubkey";
|
||||
String encryptedMessageToSend = myEncrypt(userPrivateKey, otherPubkey02, messageToSend);
|
||||
|
||||
//print("in sendDirectMessage: replyKind = $replyKind");
|
||||
@ -271,7 +271,7 @@ bool sendDeleteEvent(Store node, String eventIdToDelete) {
|
||||
} else {
|
||||
print("Event not found. Kindly ensure you have entered a valid event id.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -282,8 +282,9 @@ void reAdjustAlignment() {
|
||||
try {
|
||||
var terminalColumns = gDefaultTextWidth;
|
||||
|
||||
if( stdout.hasTerminal )
|
||||
if( stdout.hasTerminal ) {
|
||||
terminalColumns = stdout.terminalColumns;
|
||||
}
|
||||
|
||||
if( gTextWidth > terminalColumns) {
|
||||
gTextWidth = terminalColumns - 5;
|
||||
@ -291,7 +292,7 @@ void reAdjustAlignment() {
|
||||
gNumLeftMarginSpaces = (terminalColumns - gTextWidth )~/2;
|
||||
} on StdoutException catch (e) {
|
||||
print("Terminal information not available");
|
||||
if( gDebug>0) print("${e.message}");
|
||||
if( gDebug>0) print(e.message);
|
||||
gNumLeftMarginSpaces = 0;
|
||||
}
|
||||
}
|
||||
@ -317,7 +318,7 @@ void printProfile(Store node, String profilePubkey) {
|
||||
String picture = gKindONames[profilePubkey]?.picture??"";
|
||||
String lud06 = gKindONames[profilePubkey]?.lud06??"";
|
||||
String lud16 = gKindONames[profilePubkey]?.lud16??"";
|
||||
String display_name= gKindONames[profilePubkey]?.display_name??"";
|
||||
String displayName= gKindONames[profilePubkey]?.display_name??"";
|
||||
String website = gKindONames[profilePubkey]?.website??"";
|
||||
int dateLastUpdated = gKindONames[profilePubkey]?.createdAt??0;
|
||||
bool verified = gKindONames[profilePubkey]?.nip05Verified??false;
|
||||
@ -334,7 +335,7 @@ void printProfile(Store node, String profilePubkey) {
|
||||
// print LNRUL lud06 if it exists
|
||||
if( lud06.length > gMinLud06AddressLength) {
|
||||
try {
|
||||
String lud06LNString = "lightning:" + lud06;
|
||||
String lud06LNString = "lightning:$lud06";
|
||||
|
||||
List<int>? typesAndModule = getTypeAndModule(lud06LNString);
|
||||
if( typesAndModule != null) {
|
||||
@ -349,7 +350,7 @@ void printProfile(Store node, String profilePubkey) {
|
||||
// print LNRUL lud16 if it exists
|
||||
if( lud16.length > gMinLud16AddressLength) {
|
||||
try {
|
||||
String lud16LNString = "" + lud16;
|
||||
String lud16LNString = lud16;
|
||||
List<int>? typesAndModule = getTypeAndModule(lud16LNString);
|
||||
if( typesAndModule != null) {
|
||||
print("Printing lud16 address as QR:\n\n");
|
||||
@ -360,14 +361,14 @@ void printProfile(Store node, String profilePubkey) {
|
||||
}
|
||||
}
|
||||
|
||||
print("\nName : $authorName ( ${profilePubkey} ).");
|
||||
print("\nName : $authorName ( $profilePubkey ).");
|
||||
print("About : $about");
|
||||
print("Picture : $picture");
|
||||
print("display_name: $display_name");
|
||||
print("display_name: $displayName");
|
||||
print("Website : $website");
|
||||
print("Lud06 : $lud06");
|
||||
print("Lud16 : $lud16");
|
||||
print("Nip 05 : ${verified?"yes. ${nip05Id}":"no"}");
|
||||
print("Nip 05 : ${verified?"yes. $nip05Id":"no"}");
|
||||
print("\nLast Updated: ${getPrintableDate(dateLastUpdated)}\n");
|
||||
|
||||
// get the latest kind 3 event for the user, which lists his 'follows' list
|
||||
@ -389,7 +390,9 @@ void printProfile(Store node, String profilePubkey) {
|
||||
// print follow list
|
||||
stdout.write("$pronoun follow ${profileContactEvent.eventData.contactList.length} accounts: ");
|
||||
profileContactEvent.eventData.contactList.sort();
|
||||
profileContactEvent.eventData.contactList.forEach((x) => stdout.write("${getAuthorName(x.contactPubkey)}, "));
|
||||
for (var x in profileContactEvent.eventData.contactList) {
|
||||
stdout.write("${getAuthorName(x.contactPubkey)}, ");
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
|
||||
@ -397,7 +400,9 @@ void printProfile(Store node, String profilePubkey) {
|
||||
List<String> followers = node.getFollowers(profilePubkey);
|
||||
stdout.write("$pronoun have ${followers.length} followers: ");
|
||||
followers.sort((a, b) => getAuthorName(a).compareTo(getAuthorName(b)));
|
||||
followers.forEach((x) => stdout.write("${getAuthorName(x)}, "));
|
||||
for (var x in followers) {
|
||||
stdout.write("${getAuthorName(x)}, ");
|
||||
}
|
||||
print("");
|
||||
print("");
|
||||
}
|
||||
@ -436,11 +441,13 @@ void printMenu(List<String> menuOptions) {
|
||||
|
||||
var terminalColumns = gDefaultTextWidth;
|
||||
|
||||
if( stdout.hasTerminal )
|
||||
if( stdout.hasTerminal ) {
|
||||
terminalColumns = stdout.terminalColumns;
|
||||
}
|
||||
|
||||
if( longestMenuOption + 5> gMenuWidth )
|
||||
if( longestMenuOption + 5> gMenuWidth ) {
|
||||
gMenuWidth = longestMenuOption + 8;
|
||||
}
|
||||
|
||||
if( terminalColumns~/gMenuWidth > 4) {
|
||||
terminalColumns = gMenuWidth * 4;
|
||||
@ -463,7 +470,7 @@ void printMenu(List<String> menuOptions) {
|
||||
|
||||
int showMenu(List<String> menuOptions, String menuName, [String menuInfo = ""]) {
|
||||
|
||||
if(menuInfo.length > 0) {
|
||||
if(menuInfo.isNotEmpty) {
|
||||
print("\n$menuInfo\n");
|
||||
}
|
||||
|
||||
@ -531,13 +538,15 @@ Do you want to proceed. Press y/Y or n/N: """, "n");
|
||||
|
||||
void printPubkeys(Set<String> pubkey) {
|
||||
print("${myPadRight("pubkey",64)} ${myPadRight("name", 20)} ${myPadRight("about", 40)} ${myPadRight("Nip05", 30)}");
|
||||
pubkey.forEach( (x) => print("$x ${myPadRight(getAuthorName(x), 20)} ${myPadRight(gKindONames[x]?.about??"", 40)} ${myPadRight(gKindONames[x]?.nip05Id??"No", 30)}"));
|
||||
for (var x in pubkey) {
|
||||
print("$x ${myPadRight(getAuthorName(x), 20)} ${myPadRight(gKindONames[x]?.about??"", 40)} ${myPadRight(gKindONames[x]?.nip05Id??"No", 30)}");
|
||||
}
|
||||
print("");
|
||||
}
|
||||
|
||||
void printPubkeyResult(Set<String> pubkey) {
|
||||
|
||||
if( pubkey.length == 0) {
|
||||
if( pubkey.isEmpty) {
|
||||
print("There is no pubkey for that given name.");
|
||||
return;
|
||||
} else {
|
||||
@ -599,18 +608,18 @@ Future<void> otherOptionsMenuUi(Store node) async {
|
||||
String userName = getStringFromUser("Enter your new name : ", getAuthorName(userPublicKey));
|
||||
String userAbout = getStringFromUser("Enter new 'about me' for yourself : ", gKindONames[userPublicKey]?.about??"");
|
||||
String userPic = getStringFromUser("Enter url to your new display picture: ", gKindONames[userPublicKey]?.picture??"https://placekitten.com/200/200");
|
||||
String display_name = getStringFromUser("Enter your new display name : ", gKindONames[userPublicKey]?.display_name??"");
|
||||
String displayName = getStringFromUser("Enter your new display name : ", gKindONames[userPublicKey]?.display_name??"");
|
||||
String website = getStringFromUser("Enter your new website : ", gKindONames[userPublicKey]?.website??"");
|
||||
String nip05id = getStringFromUser("Enter your nip 05 id. Leave blank if unknown/none: ", gKindONames[userPublicKey]?.nip05Id??"");
|
||||
String lud06 = getStringFromUser("Enter your lud06 or lnurl. Leave blank if unknown/none: ", gKindONames[userPublicKey]?.lud06??"");
|
||||
String lud16 = getStringFromUser("Enter your lud16 address. Leave blank if unknown/none: ", gKindONames[userPublicKey]?.lud16??"");
|
||||
|
||||
String strLud06 = lud06.length > 0? '"lud06":"$lud06",': '';
|
||||
String strLud16 = lud16.length > 0? '"lud16":"$lud16",': '';
|
||||
String strDispName = display_name.length > 0? '"display_name":"$display_name",': '';
|
||||
String strWebsite = website.length > 0? '"website":"$website",': '';
|
||||
String strLud06 = lud06.isNotEmpty? '"lud06":"$lud06",': '';
|
||||
String strLud16 = lud16.isNotEmpty? '"lud16":"$lud16",': '';
|
||||
String strDispName = displayName.isNotEmpty? '"display_name":"$displayName",': '';
|
||||
String strWebsite = website.isNotEmpty? '"website":"$website",': '';
|
||||
|
||||
String content = "{\"name\": \"$userName\", \"about\": \"$userAbout\", \"picture\": \"$userPic\"${ nip05id.length >0 ? ", $strDispName $strWebsite $strLud06 $strLud16 \"nip05\": \"$nip05id\"":""}}";
|
||||
String content = "{\"name\": \"$userName\", \"about\": \"$userAbout\", \"picture\": \"$userPic\"${ nip05id.isNotEmpty ? ", $strDispName $strWebsite $strLud06 $strLud16 \"nip05\": \"$nip05id\"":""}}";
|
||||
int createdAt = DateTime.now().millisecondsSinceEpoch ~/1000;
|
||||
|
||||
EventData eventData = EventData('id', userPublicKey, createdAt, 0, content, [], [], [], [], {}, );
|
||||
@ -633,11 +642,11 @@ Future<void> otherOptionsMenuUi(Store node) async {
|
||||
|
||||
if( eventIdToDelete.length == 1) {
|
||||
String toDeleteId = eventIdToDelete.first;
|
||||
print("Going to send a delete event for the following event with id ${toDeleteId}");
|
||||
print("Going to send a delete event for the following event with id $toDeleteId");
|
||||
sendDeleteEvent(node, eventIdToDelete.first);
|
||||
await processAnyIncomingEvents(node, false); // get latest event, this takes 300 ms
|
||||
} else {
|
||||
if( eventIdToDelete.length == 0) {
|
||||
if( eventIdToDelete.isEmpty) {
|
||||
printWarning("Could not find the given event id. Kindly try again, by entering a 64 byte long hex event id, or by entering a unique prefix for the given event id.");
|
||||
} else {
|
||||
printWarning("Invalid Event Id(s). Kindly enter a more unique id.");
|
||||
@ -802,8 +811,9 @@ Future<void> channelMenuUI(Store node) async {
|
||||
Channel? channel = node.getChannelFromId(node.channels, fullChannelId);
|
||||
String actualMessage = messageToSend.substring(7);
|
||||
|
||||
if( messageToSend.indexOf(tokens[1]) + tokens[1].length < messageToSend.length)
|
||||
if( messageToSend.indexOf(tokens[1]) + tokens[1].length < messageToSend.length) {
|
||||
actualMessage = messageToSend.substring( messageToSend.indexOf(tokens[1]) + tokens[1].length + 1);
|
||||
}
|
||||
|
||||
if( channel != null) {
|
||||
await sendChannelReply(node, channel, replyTo, actualMessage, getPostKindFrom( channel.roomType));
|
||||
@ -945,7 +955,7 @@ String encryptChannelMessage(Store node, String channelId, String messageToSend)
|
||||
}
|
||||
|
||||
String priKey = keys[0], pubKey = keys[1];
|
||||
encryptedMessage = myEncrypt(priKey, "02" + pubKey, messageToSend);
|
||||
encryptedMessage = myEncrypt(priKey, "02$pubKey", messageToSend);
|
||||
|
||||
return encryptedMessage;
|
||||
}
|
||||
@ -983,9 +993,9 @@ Future<void> addUsersToEncryptedChannel(Store node, String fullChannelId, Set<St
|
||||
String content = channelEvent.eventData.content;
|
||||
|
||||
String tags = '["e","$fullChannelId"]';
|
||||
participants.forEach((participant) {
|
||||
tags += ',["p","${participant}"]';
|
||||
});
|
||||
for (var participant in participants) {
|
||||
tags += ',["p","$participant"]';
|
||||
}
|
||||
|
||||
int numNewUsers = participants.length;
|
||||
|
||||
@ -1142,8 +1152,9 @@ Future<void> encryptedChannelMenuUI(Store node) async {
|
||||
String replyTo = tokens[1];
|
||||
String actualMessage = messageToSend.substring(7);
|
||||
|
||||
if( messageToSend.indexOf(tokens[1]) + tokens[1].length < messageToSend.length)
|
||||
if( messageToSend.indexOf(tokens[1]) + tokens[1].length < messageToSend.length) {
|
||||
actualMessage = messageToSend.substring( messageToSend.indexOf(tokens[1]) + tokens[1].length + 1);
|
||||
}
|
||||
|
||||
String encryptedMessageToSend = encryptChannelMessage(node, fullChannelId, actualMessage);
|
||||
if( encryptedMessageToSend != "") {
|
||||
@ -1439,7 +1450,9 @@ Future<void> socialMenuUi(Store node) async {
|
||||
if( numPrinted[0] == 0) {
|
||||
print("\nNot found in the last $gHoursDefaultPrint hours. Try increasing the number of days printed, from social network options to search further back into history.\n");
|
||||
}
|
||||
} else printWarning("Blank word entered. Try again.");
|
||||
} else {
|
||||
printWarning("Blank word entered. Try again.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@ -1542,7 +1555,7 @@ Future<void> socialMenuUi(Store node) async {
|
||||
stdout.write("Printing profile of a user; type username or first few letters of user's public key( or full public key): ");
|
||||
String? $tempUserName = stdin.readLineSync();
|
||||
String userName = $tempUserName??"";
|
||||
stdout.write( "user name: " + userName);
|
||||
stdout.write( "user name: $userName");
|
||||
if( userName != "") {
|
||||
Set<String> pubkey = getPublicKeyFromName(userName);
|
||||
|
||||
@ -1578,7 +1591,7 @@ Future<void> socialMenuUi(Store node) async {
|
||||
continue;
|
||||
} on Exception catch (e) {
|
||||
printWarning("Invalid input. Kindly try again.");
|
||||
if( gDebug > 0) print(" ${e}");
|
||||
if( gDebug > 0) print(" $e");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -1600,8 +1613,9 @@ void directRoomNotifications(Store node, [int x = 0, int y = 0]) {
|
||||
bool showNotifications (ScrollableMessages room) => room.selectorNotifications();
|
||||
int numDirectRoomsPrinted = node.printDirectRoomsOverview( showNotifications, 100, node.allChildEventsMap);
|
||||
|
||||
if( numDirectRoomsPrinted > 0)
|
||||
print("\n");
|
||||
if( numDirectRoomsPrinted > 0) {
|
||||
print("\n");
|
||||
}
|
||||
|
||||
int totalNotifications = numPrinted[2] + numDirectRoomsPrinted;
|
||||
if( totalNotifications > 0) {
|
||||
@ -1691,7 +1705,7 @@ Future<void> mainMenuUi(Store node) async {
|
||||
mainMenuContinue = false;
|
||||
String authorName = getAuthorName(userPublicKey);
|
||||
clearScreen();
|
||||
print("\nFinished Nostr session for user: ${authorName} ($userPublicKey)");
|
||||
print("\nFinished Nostr session for user: $authorName ($userPublicKey)");
|
||||
if( gEventsFilename != "") {
|
||||
await node.writeEventsToFile(gEventsFilename);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class UserNameInfo {
|
||||
Event ?latestContactEvent;
|
||||
bool nip05Verified;
|
||||
String? nip05Id;
|
||||
UserNameInfo(this.createdAt, this.name, this.about, this.picture, this.lud06, this.lud16, this.display_name, this.website, this.nip05Id , this.latestContactEvent, [this.createdAtKind3 = null, this.nip05Verified = false]);
|
||||
UserNameInfo(this.createdAt, this.name, this.about, this.picture, this.lud06, this.lud16, this.display_name, this.website, this.nip05Id , this.latestContactEvent, [this.createdAtKind3, this.nip05Verified = false]);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -59,7 +59,7 @@ Set<String> getReactorPubkeys(String eventId) {
|
||||
List<List<String>>? reactions = gReactions[eventId];
|
||||
|
||||
if( reactions != null) {
|
||||
reactions.forEach((reaction) { reactorIds.add(reaction[0]);});
|
||||
for (var reaction in reactions) { reactorIds.add(reaction[0]);}
|
||||
}
|
||||
|
||||
return reactorIds;
|
||||
@ -157,22 +157,22 @@ class EventData {
|
||||
}
|
||||
|
||||
// then depending on the numbers and values ( of root and replyto) return the parent
|
||||
if( replyId.length > 0) {
|
||||
if( replyId.isNotEmpty) {
|
||||
if( numReply == 1) {
|
||||
return replyId;
|
||||
} else {
|
||||
// if there are multiply reply's we can't tell which is which, so we return the one at top
|
||||
if( replyId.length > 0) {
|
||||
if( replyId.isNotEmpty) {
|
||||
return replyId;
|
||||
} else {
|
||||
// this is case when there is no reply id . should not actually happen given if conditions
|
||||
if( rootId.length > 0) {
|
||||
if( rootId.isNotEmpty) {
|
||||
return rootId;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if( rootId.length > 0) {
|
||||
if( rootId.isNotEmpty) {
|
||||
//printWarning("returning root id. no reply id found.");
|
||||
return rootId;
|
||||
}
|
||||
@ -209,7 +209,7 @@ class EventData {
|
||||
}
|
||||
|
||||
List<String>? getTTags() {
|
||||
List<String>? tTags = null;
|
||||
List<String>? tTags;
|
||||
|
||||
for( int i = 0; i < tags.length; i++) {
|
||||
List<String> tag = tags[i];
|
||||
@ -217,9 +217,7 @@ class EventData {
|
||||
continue;
|
||||
}
|
||||
if( tag[0] == 't') {
|
||||
if( tTags == null ) {
|
||||
tTags = [];
|
||||
}
|
||||
tTags ??= [];
|
||||
|
||||
tTags.add(tag[1]);
|
||||
}
|
||||
@ -268,7 +266,7 @@ class EventData {
|
||||
try {
|
||||
verifyEvent(json);
|
||||
|
||||
} on Exception catch(e) {
|
||||
} on Exception {
|
||||
//printWarning("verify gave exception $e");
|
||||
throw Exception("in Event constructor: sig verify gave exception");
|
||||
}
|
||||
@ -364,7 +362,7 @@ class EventData {
|
||||
String author = getAuthorName(mentionedId);
|
||||
return "@$author";
|
||||
} else {
|
||||
EventData? eventData = tempChildEventsMap[mentionedId]?.event.eventData??null;
|
||||
EventData? eventData = tempChildEventsMap[mentionedId]?.event.eventData;
|
||||
if( eventData != null) {
|
||||
String quotedAuthor = getAuthorName(eventData.pubkey);
|
||||
String prefixId = mentionedId.substring(0, 3);
|
||||
@ -401,7 +399,7 @@ class EventData {
|
||||
}
|
||||
|
||||
// replace the mentions, if any are found
|
||||
String mentionStr = "(\#\[[0-9]+\])";
|
||||
String mentionStr = "(#[[0-9]+])";
|
||||
RegExp mentionRegExp = RegExp(mentionStr);
|
||||
content = content.replaceAllMapped(mentionRegExp, replaceMentions);
|
||||
return content;
|
||||
@ -468,7 +466,7 @@ class EventData {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!isValidDirectMessage(this, acceptableKind: this.kind)) {
|
||||
if(!isValidDirectMessage(this, acceptableKind: kind)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -577,19 +575,19 @@ class EventData {
|
||||
int ivIndex = content.indexOf("?iv=");
|
||||
if( ivIndex > 0) {
|
||||
var iv = content.substring( ivIndex + 4, content.length);
|
||||
var enc_str = content.substring(0, ivIndex);
|
||||
var encStr = content.substring(0, ivIndex);
|
||||
|
||||
String userKey = userPrivateKey ;
|
||||
String otherUserPubKey = "02" + pubkey;
|
||||
String otherUserPubKey = "02$pubkey";
|
||||
if( pubkey == userPublicKey) { // if user themselve is the sender change public key used to decrypt
|
||||
userKey = userPrivateKey;
|
||||
int numPtags = 0;
|
||||
tags.forEach((tag) {
|
||||
for (var tag in tags) {
|
||||
if(tag[0] == "p" ) {
|
||||
otherUserPubKey = "02" + tag[1];
|
||||
otherUserPubKey = "02${tag[1]}";
|
||||
numPtags++;
|
||||
}
|
||||
});
|
||||
}
|
||||
// if there are more than one p tags, we don't know who its for
|
||||
if( numPtags != 1) {
|
||||
if( gDebug >= 0) printInColor(" in translateAndExpand: got event $id with number of p tags != one : $numPtags . not decrypting", redColor);
|
||||
@ -597,7 +595,7 @@ class EventData {
|
||||
}
|
||||
}
|
||||
|
||||
var decrypted = myPrivateDecrypt( userKey, otherUserPubKey, enc_str, iv); // use bob's privatekey and alic's publickey means bob can read message from alic
|
||||
var decrypted = myPrivateDecrypt( userKey, otherUserPubKey, encStr, iv); // use bob's privatekey and alic's publickey means bob can read message from alic
|
||||
return decrypted;
|
||||
} else {
|
||||
if(gDebug > 0) print("Invalid content for dm, could not get ivIndex: $content");
|
||||
@ -629,7 +627,7 @@ class EventData {
|
||||
return null;
|
||||
}
|
||||
var iv = content.substring( ivIndex + 4, content.length);
|
||||
var enc_str = content.substring(0, ivIndex);
|
||||
var encStr = content.substring(0, ivIndex);
|
||||
|
||||
String channelId = getChannelIdForKind4x();
|
||||
List<String> keys = [];
|
||||
@ -642,9 +640,9 @@ class EventData {
|
||||
}
|
||||
|
||||
String priKey = keys[0];
|
||||
String pubKey = "02" + keys[1];
|
||||
String pubKey = "02${keys[1]}";
|
||||
|
||||
var decrypted = myPrivateDecrypt( priKey, pubKey, enc_str, iv); // use bob's privatekey and alic's publickey means bob can read message from alic
|
||||
var decrypted = myPrivateDecrypt( priKey, pubKey, encStr, iv); // use bob's privatekey and alic's publickey means bob can read message from alic
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
@ -657,7 +655,7 @@ class EventData {
|
||||
// get first e tag, which should be the channel of which this is part of
|
||||
for( int i = 0; i < eTags.length; i++) {
|
||||
List tag = eTags[i];
|
||||
if( tag.length >= 1) {
|
||||
if( tag.isNotEmpty) {
|
||||
return tag[0];
|
||||
}
|
||||
}
|
||||
@ -665,7 +663,7 @@ class EventData {
|
||||
}
|
||||
|
||||
String getChannelIdForTTagRoom(String tagValue) {
|
||||
return tagValue + " #t";
|
||||
return "$tagValue #t";
|
||||
}
|
||||
|
||||
// only applicable for kind 42/142 event; returns the channel 40/140 id of which the event is part of
|
||||
@ -687,9 +685,9 @@ class EventData {
|
||||
|
||||
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
|
||||
if( tempChildEventsMap != null )
|
||||
if(kind == 4)
|
||||
if(kind == 4) {
|
||||
translateAndDecryptKind4( tempChildEventsMap);
|
||||
else if ([1, 42].contains(kind)) {
|
||||
} else if ([1, 42].contains(kind)) {
|
||||
translateAndExpandMentions(tempChildEventsMap);
|
||||
} else if ([142].contains(kind)) {
|
||||
if( secretMessageIds != null && encryptedChannels != null) {
|
||||
@ -752,7 +750,7 @@ class EventData {
|
||||
strToPrint += "█";
|
||||
}
|
||||
|
||||
strToPrint += "${name}: ";
|
||||
strToPrint += "$name: ";
|
||||
const int typicalxLen = "|id: 82b5 , 12:04 AM Sep 19".length + 5; // not sure where 5 comes from
|
||||
List<dynamic> reactionString = getReactionStr(depth);
|
||||
//print("\n|${reactionString[0]}|\n ${ reactionString[1]}\n }");
|
||||
@ -781,8 +779,9 @@ class EventData {
|
||||
|
||||
// effective len of last line is used to calcluate where the idDateLikes str is affixed at the end
|
||||
int effectiveLastLineLen = lastLineLen - gSpacesPerDepth * depth - effectiveNameFieldLen - gNumLeftMarginSpaces;
|
||||
if( contentShifted.length <= maxLineLen )
|
||||
if( contentShifted.length <= maxLineLen ) {
|
||||
effectiveLastLineLen = contentShifted.length;
|
||||
}
|
||||
|
||||
// needed to use this because the color padding in notifications reactions will mess up the length calculation in the actual reaction string
|
||||
int colorStrLen = reactionString[0].length - reactionString[1];
|
||||
@ -791,20 +790,20 @@ class EventData {
|
||||
if( (gSpacesPerDepth * depth + effectiveNameFieldLen + effectiveLastLineLen + idDateLikes.length ) <= gTextWidth) {
|
||||
idDateLikes = idDateLikes.padLeft((gTextWidth ) + colorStrLen - (gSpacesPerDepth * depth + effectiveNameFieldLen + effectiveLastLineLen));
|
||||
} else {
|
||||
idDateLikes = "\n" + idDateLikes.padLeft(gNumLeftMarginSpaces + gTextWidth + colorStrLen);
|
||||
idDateLikes = "\n${idDateLikes.padLeft(gNumLeftMarginSpaces + gTextWidth + colorStrLen)}";
|
||||
}
|
||||
|
||||
// print content and the dateslikes string
|
||||
strToPrint += getStrInColor(contentShifted + idDateLikes + "\n", commentColor);
|
||||
strToPrint += getStrInColor("$contentShifted$idDateLikes\n", commentColor);
|
||||
stdout.write(strToPrint);
|
||||
}
|
||||
|
||||
String getAsLine(var tempChildEventsMap, Set<String>? secretMessageIds, List<Channel>? encryptedChannels, {int len = 20}) {
|
||||
|
||||
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
|
||||
if(kind == 4)
|
||||
if(kind == 4) {
|
||||
translateAndDecryptKind4( tempChildEventsMap);
|
||||
else if ([1, 42].contains(kind)) {
|
||||
} else if ([1, 42].contains(kind)) {
|
||||
translateAndExpandMentions(tempChildEventsMap);
|
||||
} else if ([142].contains(kind)) {
|
||||
if( tempChildEventsMap != null && secretMessageIds != null && encryptedChannels != null) {
|
||||
@ -839,12 +838,12 @@ class EventData {
|
||||
|
||||
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
|
||||
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
|
||||
if(kind == 4)
|
||||
if(kind == 4) {
|
||||
translateAndDecryptKind4( tempChildEventsMap);
|
||||
else if ([1, 42].contains(kind)) {
|
||||
} else if ([1, 42].contains(kind)) {
|
||||
translateAndExpandMentions(tempChildEventsMap);
|
||||
} else if ([142].contains(kind)) {
|
||||
if( tempChildEventsMap != null && secretMessageIds != null && encryptedChannels != null) {
|
||||
if( secretMessageIds != null && encryptedChannels != null) {
|
||||
//print('decrypting 14x in getStrForChannel');
|
||||
translateAndDecrypt14x(secretMessageIds, encryptedChannels, tempChildEventsMap);
|
||||
}
|
||||
@ -867,8 +866,9 @@ class EventData {
|
||||
tempEvaluatedContent = tempContent = content; // content would be changed so show that
|
||||
}
|
||||
|
||||
if( tempEvaluatedContent=="")
|
||||
if( tempEvaluatedContent=="") {
|
||||
tempEvaluatedContent = tempContent;
|
||||
}
|
||||
|
||||
const int nameWidthDepth = 16~/gSpacesPerDepth; // how wide name will be in depth spaces
|
||||
const int timeWidthDepth = 18~/gSpacesPerDepth;
|
||||
@ -900,13 +900,13 @@ class EventData {
|
||||
if( replyToEvent.eventData.evaluatedContent.length <= gReplyLengthPrinted){
|
||||
replyToPrint = replyToEvent.eventData.evaluatedContent;
|
||||
} else {
|
||||
replyToPrint = replyToEvent.eventData.evaluatedContent.substring(0, gReplyLengthPrinted) + "...";
|
||||
replyToPrint = "${replyToEvent.eventData.evaluatedContent.substring(0, gReplyLengthPrinted)}...";
|
||||
}
|
||||
strReplyTo = 'In reply to:"${getAuthorName(replyToEvent.eventData.pubkey)}: $replyToPrint"';
|
||||
strReplyTo = makeParagraphAtDepth(strReplyTo, finalContentDepthInSpaces + 6); // one extra for content
|
||||
|
||||
// add reply to string to end of the content. How it will show:
|
||||
contentShifted += ( "\n" + getNumSpaces( contentPlacementColumn + gSpacesPerDepth) + strReplyTo);
|
||||
contentShifted += ( "\n${getNumSpaces( contentPlacementColumn + gSpacesPerDepth)}$strReplyTo");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -916,10 +916,10 @@ class EventData {
|
||||
String msgId = id.substring(0, 3).padLeft(gSpacesPerDepth~/2).padRight(gSpacesPerDepth) ;
|
||||
|
||||
if( isNotification) {
|
||||
strToPrint = "$gNotificationColor${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: $gNotificationColor" + contentShifted + gColorEndMarker;
|
||||
strToPrint = "$gNotificationColor${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: $gNotificationColor$contentShifted$gColorEndMarker";
|
||||
isNotification = false;
|
||||
} else {
|
||||
strToPrint = "${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: " + contentShifted;
|
||||
strToPrint = "${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: $contentShifted";
|
||||
}
|
||||
return strToPrint;
|
||||
}
|
||||
@ -956,8 +956,9 @@ class EventData {
|
||||
firstEntry = false;
|
||||
} else {
|
||||
// this is normal printing of the reaction. only print for + for now
|
||||
if( reactors[i][1] == "+")
|
||||
if( reactors[i][1] == "+") {
|
||||
authorName = getAuthorName(reactorId);
|
||||
}
|
||||
reactorNames += comma + authorName;
|
||||
len += (2 + authorName.length);
|
||||
firstEntry = false;
|
||||
@ -979,14 +980,14 @@ class EventData {
|
||||
|
||||
// returns the last e tag as reply to event for kind 42 and 142 events
|
||||
Event? getReplyToChannelEvent(Map<String, Tree> tempChildEventsMap) {
|
||||
switch (this.kind) {
|
||||
switch (kind) {
|
||||
case 42:
|
||||
case 142:
|
||||
for(int i = tags.length - 1; i >= 0; i--) {
|
||||
List tag = tags[i];
|
||||
if( tag[0] == 'e') {
|
||||
String replyToEventId = tag[1];
|
||||
Event? eventInReplyTo = (gStore?.allChildEventsMap[replyToEventId]?.event)??null;
|
||||
Event? eventInReplyTo = (gStore?.allChildEventsMap[replyToEventId]?.event);
|
||||
if( eventInReplyTo != null) {
|
||||
// add 1 cause 42 can reply to or tag kind 1, and we'll show that kind 1
|
||||
if ( [1,42,142].contains( eventInReplyTo.eventData.kind)) {
|
||||
@ -1039,14 +1040,15 @@ class Event {
|
||||
}
|
||||
|
||||
EventData newEventData = EventData.fromJson(json[2]);
|
||||
if( !fromFile)
|
||||
if( !fromFile) {
|
||||
newEventData.isNotification = true;
|
||||
}
|
||||
return Event(json[0] as String, json[1] as String, newEventData, [relay], d, fromFile );
|
||||
} on Exception catch(e) {
|
||||
if( gDebug > 0) {
|
||||
print("Could not create event. $e\nproblem str: $d\n");
|
||||
}
|
||||
throw e;
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1115,7 +1117,7 @@ bool processKind0Event(Event e) {
|
||||
String picture = "";
|
||||
String lud06 = "";
|
||||
String lud16 = "";
|
||||
String display_name = "";
|
||||
String displayName = "";
|
||||
String website = "";
|
||||
String nip05 = "";
|
||||
|
||||
@ -1126,7 +1128,7 @@ bool processKind0Event(Event e) {
|
||||
picture = json["picture"]??"";
|
||||
lud06 = json["lud06"]??"";
|
||||
lud16 = json["lud16"]??"";
|
||||
display_name = json["display_name"]??"";
|
||||
displayName = json["display_name"]??"";
|
||||
website = json["website"]??"";
|
||||
nip05 = json['nip05']??"";
|
||||
//String twitterId = json['twitter']??"";
|
||||
@ -1137,12 +1139,12 @@ bool processKind0Event(Event e) {
|
||||
|
||||
bool newEntry = false, entryModified = false;
|
||||
if( !gKindONames.containsKey(e.eventData.pubkey)) {
|
||||
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, display_name, website, nip05, null);
|
||||
newEntry = true;;
|
||||
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, displayName, website, nip05, null);
|
||||
newEntry = true;
|
||||
} else {
|
||||
int oldTime = gKindONames[e.eventData.pubkey]?.createdAt??0;
|
||||
if( oldTime < e.eventData.createdAt) {
|
||||
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, display_name, website, nip05, null);
|
||||
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, displayName, website, nip05, null);
|
||||
entryModified = true;
|
||||
}
|
||||
}
|
||||
@ -1154,13 +1156,13 @@ bool processKind0Event(Event e) {
|
||||
bool localDebug = false; //e.eventData.pubkey == "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437"? true: false;
|
||||
|
||||
if( newEntry || entryModified) {
|
||||
if(nip05.length > 0) {
|
||||
if(nip05.isNotEmpty) {
|
||||
List<String> urlSplit = nip05.split("@");
|
||||
if( urlSplit.length == 2) {
|
||||
|
||||
String urlNip05 = urlSplit[1] + "/.well-known/nostr.json?name=" + urlSplit[0];
|
||||
String urlNip05 = "${urlSplit[1]}/.well-known/nostr.json?name=${urlSplit[0]}";
|
||||
if( !urlNip05.startsWith("http")) {
|
||||
urlNip05 = "http://"+ urlNip05;
|
||||
urlNip05 = "http://$urlNip05";
|
||||
}
|
||||
|
||||
fetchNip05Info(urlNip05)
|
||||
@ -1178,7 +1180,7 @@ bool processKind0Event(Event e) {
|
||||
int oldTime = 0;
|
||||
if( !gKindONames.containsKey(e.eventData.pubkey)) {
|
||||
//printWarning("in response handing. creating user info");
|
||||
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, display_name, website,null, null);
|
||||
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, displayName, website,null, null);
|
||||
} else {
|
||||
oldTime = gKindONames[e.eventData.pubkey]?.createdAt??0;
|
||||
//print("in response handing. user info exists with old time = $oldTime and this event time = ${e.eventData.createdAt}");
|
||||
@ -1215,23 +1217,23 @@ bool processKind3Event(Event newContactEvent) {
|
||||
bool newEntry = false, entryModified = false;
|
||||
if( !gKindONames.containsKey(newContactEvent.eventData.pubkey)) {
|
||||
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(null, null, null, null, null, null, null, null, null, newContactEvent, newContactEvent.eventData.createdAt);
|
||||
newEntry = true;;
|
||||
newEntry = true;
|
||||
} else {
|
||||
// if entry already exists, then check its old time and update only if we have a newer entry now
|
||||
int oldTime = gKindONames[newContactEvent.eventData.pubkey]?.createdAtKind3??0;
|
||||
if( oldTime < newContactEvent.eventData.createdAt) {
|
||||
int? createdAt = gKindONames[newContactEvent.eventData.pubkey]?.createdAt??null;
|
||||
int? createdAt = gKindONames[newContactEvent.eventData.pubkey]?.createdAt;
|
||||
String? name = gKindONames[newContactEvent.eventData.pubkey]?.name,
|
||||
about = gKindONames[newContactEvent.eventData.pubkey]?.about,
|
||||
picture = gKindONames[newContactEvent.eventData.pubkey]?.picture,
|
||||
lud06 = gKindONames[newContactEvent.eventData.pubkey]?.lud06,
|
||||
lud16 = gKindONames[newContactEvent.eventData.pubkey]?.lud16,
|
||||
display_name = gKindONames[newContactEvent.eventData.pubkey]?.display_name,
|
||||
displayName = gKindONames[newContactEvent.eventData.pubkey]?.display_name,
|
||||
website = gKindONames[newContactEvent.eventData.pubkey]?.website,
|
||||
nip05id = gKindONames[newContactEvent.eventData.pubkey]?.nip05Id??"";
|
||||
|
||||
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(createdAt, name, about, picture, lud06, lud16, display_name, website, nip05id, newContactEvent, newContactEvent.eventData.createdAt );
|
||||
entryModified = true;;
|
||||
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(createdAt, name, about, picture, lud06, lud16, displayName, website, nip05id, newContactEvent, newContactEvent.eventData.createdAt );
|
||||
entryModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1260,16 +1262,16 @@ String getNip05Name( String pubkey) {
|
||||
// returns name by looking up global list gKindONames, which is populated by kind 0 events
|
||||
String getAuthorName(String pubkey, {int maxDisplayLen = gMaxInteger, int pubkeyLenShown = 5}) {
|
||||
|
||||
if( gFollowList.length == 0) {
|
||||
if( gFollowList.isEmpty) {
|
||||
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 = "";
|
||||
if( gKindONames[pubkey]?.name == null || gKindONames[pubkey]?.name?.length == 0)
|
||||
name = maxLen(pubkey);
|
||||
else {
|
||||
if( gKindONames[pubkey]?.name == null || gKindONames[pubkey]?.name?.length == 0) {
|
||||
name = maxLen(pubkey);
|
||||
} else {
|
||||
name = (gKindONames[pubkey]?.name)??maxLen(pubkey);
|
||||
}
|
||||
|
||||
@ -1291,7 +1293,7 @@ String getAuthorName(String pubkey, {int maxDisplayLen = gMaxInteger, int pubkey
|
||||
|
||||
// returns full public key(s) for the given username( which can be first few letters of pubkey, or the user name)
|
||||
Set<String> getPublicKeyFromName(String inquiredName) {
|
||||
if( inquiredName.length < 1) {
|
||||
if( inquiredName.isEmpty) {
|
||||
return {};
|
||||
}
|
||||
Set<String> pubkeys = {};
|
||||
@ -1337,8 +1339,9 @@ void printDepth(int d) {
|
||||
void printCenteredHeadline(displayName) {
|
||||
int numDashes = 10; // num of dashes on each side
|
||||
int startText = gNumLeftMarginSpaces + ( gTextWidth - (displayName.length + 2 * numDashes)) ~/ 2;
|
||||
if( startText < 0)
|
||||
if( startText < 0) {
|
||||
startText = 0;
|
||||
}
|
||||
|
||||
String str = getNumSpaces(startText) + getNumDashes(numDashes) + displayName + getNumDashes(numDashes);
|
||||
print(str);
|
||||
@ -1369,7 +1372,7 @@ String makeParagraphAtDepth(String s, int depthInSpaces) {
|
||||
String line = listCulledLine[0];
|
||||
int lenReturned = listCulledLine[1] as int;
|
||||
|
||||
if( line.length == 0 || lenReturned == 0) break;
|
||||
if( line.isEmpty || lenReturned == 0) break;
|
||||
|
||||
newString += line;
|
||||
startIndex += lenReturned;
|
||||
@ -1381,8 +1384,9 @@ String makeParagraphAtDepth(String s, int depthInSpaces) {
|
||||
// returns from string[startIndex:] the first len number of chars. no newline is added.
|
||||
List getLineWithMaxLen(String s, int startIndex, int lenPerLine, String spacesString, List<List<int>> urlRanges) {
|
||||
|
||||
if( startIndex >= s.length)
|
||||
if( startIndex >= s.length) {
|
||||
return ["", 0];
|
||||
}
|
||||
|
||||
String line = ""; // is returned
|
||||
|
||||
@ -1420,7 +1424,9 @@ List getLineWithMaxLen(String s, int startIndex, int lenPerLine, String spacesSt
|
||||
int i = line.length - 1;
|
||||
|
||||
// find a whitespace character
|
||||
for( ; i > 0 && !isWordSeparater(line[i]); i--);
|
||||
for( ; i > 0 && !isWordSeparater(line[i]); i--) {
|
||||
{}
|
||||
}
|
||||
// for ended
|
||||
|
||||
if( line.length - i < gMaxLenUnbrokenWord) {
|
||||
@ -1428,9 +1434,10 @@ List getLineWithMaxLen(String s, int startIndex, int lenPerLine, String spacesSt
|
||||
// break the line here if its a word separator
|
||||
if( isWordSeparater(line[i])) {
|
||||
int newLineStart = i + 1;
|
||||
if( line[i] != ' ')
|
||||
if( line[i] != ' ') {
|
||||
newLineStart = i;
|
||||
line = line.substring(0, i) + "\n" + spacesString + line.substring(newLineStart, line.length);
|
||||
}
|
||||
line = "${line.substring(0, i)}\n$spacesString${line.substring(newLineStart, line.length)}";
|
||||
lineBroken = true;
|
||||
}
|
||||
}
|
||||
@ -1494,16 +1501,16 @@ bool isValidDirectMessage(EventData directMessageData, {int acceptableKind = 4})
|
||||
bool validUserMessage = false;
|
||||
List<String> allPtags = [];
|
||||
|
||||
directMessageData.tags.forEach((tag) {
|
||||
for (var tag in directMessageData.tags) {
|
||||
if( tag.length < 2 ) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if( tag[0] == "p" && tag[1].length == 64) { // basic length sanity test
|
||||
allPtags.add(tag[1]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(gDebug >= 0 && gCheckEventId == directMessageData.id) print("In isvalid direct message: ptags len: ${allPtags.length}, ptags = ${allPtags}");
|
||||
if(gDebug >= 0 && gCheckEventId == directMessageData.id) print("In isvalid direct message: ptags len: ${allPtags.length}, ptags = $allPtags");
|
||||
|
||||
if( directMessageData.pubkey == userPublicKey && allPtags.length == 1) {
|
||||
if( allPtags[0].substring(0, 32) != "0".padLeft(32, '0')) { // check that the message hasn't been sent to an invalid pubkey
|
||||
@ -1524,16 +1531,16 @@ bool isValidDirectMessage(EventData directMessageData, {int acceptableKind = 4})
|
||||
|
||||
String getRandomPrivKey() {
|
||||
FortunaRandom fr = FortunaRandom();
|
||||
final _sGen = Random.secure();;
|
||||
final sGen = Random.secure();
|
||||
fr.seed(KeyParameter(
|
||||
Uint8List.fromList(List.generate(32, (_) => _sGen.nextInt(255)))));
|
||||
Uint8List.fromList(List.generate(32, (_) => sGen.nextInt(255)))));
|
||||
|
||||
BigInt randomNumber = fr.nextBigInteger(256);
|
||||
String strKey = randomNumber.toRadixString(16);
|
||||
if( strKey.length < 64) {
|
||||
int numZeros = 64 - strKey.length;
|
||||
for(int i = 0; i < numZeros; i++) {
|
||||
strKey = "0" + strKey;
|
||||
strKey = "0$strKey";
|
||||
}
|
||||
}
|
||||
return strKey;
|
||||
@ -1568,7 +1575,7 @@ Uint8List myPrivateDecryptRaw( String privateString,
|
||||
}
|
||||
|
||||
if( byteSecret.isEmpty) {
|
||||
byteSecret = Kepler.byteSecret(privateString, publicString);;
|
||||
byteSecret = Kepler.byteSecret(privateString, publicString);
|
||||
gMapByteSecret[publicString] = byteSecret;
|
||||
}
|
||||
|
||||
@ -1578,11 +1585,11 @@ Uint8List myPrivateDecryptRaw( String privateString,
|
||||
? convert.base64.decode(b64IV)
|
||||
: Uint8List.fromList(secretIV[1]);
|
||||
|
||||
CipherParameters params = new PaddedBlockCipherParameters(
|
||||
new ParametersWithIV(new KeyParameter(key), iv), null);
|
||||
CipherParameters params = PaddedBlockCipherParameters(
|
||||
ParametersWithIV(KeyParameter(key), iv), null);
|
||||
|
||||
PaddedBlockCipherImpl cipherImpl = new PaddedBlockCipherImpl(
|
||||
new PKCS7Padding(), new CBCBlockCipher(new AESEngine()));
|
||||
PaddedBlockCipherImpl cipherImpl = PaddedBlockCipherImpl(
|
||||
PKCS7Padding(), CBCBlockCipher(AESEngine()));
|
||||
|
||||
cipherImpl.init(false,
|
||||
params as PaddedBlockCipherParameters<CipherParameters?,
|
||||
@ -1620,16 +1627,16 @@ String myEncryptRaw( String privateString,
|
||||
|
||||
// generate iv https://stackoverflow.com/questions/63630661/aes-engine-not-initialised-with-pointycastle-securerandom
|
||||
FortunaRandom fr = FortunaRandom();
|
||||
final _sGen = Random.secure();;
|
||||
final sGen = Random.secure();
|
||||
fr.seed(KeyParameter(
|
||||
Uint8List.fromList(List.generate(32, (_) => _sGen.nextInt(255)))));
|
||||
Uint8List.fromList(List.generate(32, (_) => sGen.nextInt(255)))));
|
||||
final iv = fr.nextBytes(16);
|
||||
|
||||
CipherParameters params = new PaddedBlockCipherParameters(
|
||||
new ParametersWithIV(new KeyParameter(key), iv), null);
|
||||
CipherParameters params = PaddedBlockCipherParameters(
|
||||
ParametersWithIV(KeyParameter(key), iv), null);
|
||||
|
||||
PaddedBlockCipherImpl cipherImpl = new PaddedBlockCipherImpl(
|
||||
new PKCS7Padding(), new CBCBlockCipher(new AESEngine()));
|
||||
PaddedBlockCipherImpl cipherImpl = PaddedBlockCipherImpl(
|
||||
PKCS7Padding(), CBCBlockCipher(AESEngine()));
|
||||
|
||||
cipherImpl.init(true, // means to encrypt
|
||||
params as PaddedBlockCipherParameters<CipherParameters?,
|
||||
@ -1647,16 +1654,14 @@ String myEncryptRaw( String privateString,
|
||||
offset += cipherImpl.doFinal(uintInputText, offset, outputEncodedText, offset);
|
||||
final Uint8List finalEncodedText = outputEncodedText.sublist(0, offset);
|
||||
|
||||
String stringIv = convert.base64.encode(iv);;
|
||||
String stringIv = convert.base64.encode(iv);
|
||||
String outputPlainText = convert.base64.encode(finalEncodedText);
|
||||
outputPlainText = outputPlainText + "?iv=" + stringIv;
|
||||
outputPlainText = "$outputPlainText?iv=$stringIv";
|
||||
return outputPlainText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read events from file. a flag is set for such events, so that when writing events back, the ones read from file aren't added, and only
|
||||
* new events from relays are written to file.
|
||||
*/
|
||||
/// Read events from file. a flag is set for such events, so that when writing events back, the ones read from file aren't added, and only
|
||||
/// new events from relays are written to file.
|
||||
Set<Event> readEventsFromFile(String filename) {
|
||||
Set<Event> events = {};
|
||||
final File file = File(filename);
|
||||
@ -1709,7 +1714,7 @@ String myGetPublicKey(String prikey) {
|
||||
if( pubkey.length < 64) {
|
||||
int numZeros = 64 - pubkey.length;
|
||||
for(int i = 0; i < numZeros; i++) {
|
||||
pubkey = "0" + pubkey;
|
||||
pubkey = "0$pubkey";
|
||||
}
|
||||
}
|
||||
return pubkey;
|
||||
|
@ -63,7 +63,7 @@ class Relays {
|
||||
|
||||
void getKindEvents(List<int> kind, String relayUrl, int limit, int sinceWhen) {
|
||||
kind.toString();
|
||||
String subscriptionId = "kind_" + kind.toString() + "_" + relayUrl.substring(6);
|
||||
String subscriptionId = "kind_${kind}_${relayUrl.substring(6)}";
|
||||
String request = getKindRequest(subscriptionId, kind, limit, sinceWhen);
|
||||
|
||||
sendRequest(relayUrl, request);
|
||||
@ -79,20 +79,21 @@ class Relays {
|
||||
}
|
||||
}
|
||||
|
||||
String subscriptionId = "single_user" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6);
|
||||
String subscriptionId = "single_user${relays[relayUrl]?.numRequestsSent??""}_${relayUrl.substring(6)}";
|
||||
if( relays.containsKey(relayUrl)) {
|
||||
Set<String>? users = relays[relayUrl]?.users;
|
||||
if( users != null) { // get a user only if it has not already been requested
|
||||
// following is too restrictive casuse changed sinceWhen is not considered. TODO improve it
|
||||
bool alreadyRecevied = false;
|
||||
users.forEach((user) {
|
||||
for (var user in users) {
|
||||
if( user == publicKey) {
|
||||
alreadyRecevied = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if( alreadyRecevied)
|
||||
if( alreadyRecevied) {
|
||||
return;
|
||||
}
|
||||
|
||||
users.add(publicKey);
|
||||
}
|
||||
@ -110,7 +111,7 @@ class Relays {
|
||||
}
|
||||
}
|
||||
|
||||
String subscriptionId = "mention" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6);
|
||||
String subscriptionId = "mention${relays[relayUrl]?.numRequestsSent??""}_${relayUrl.substring(6)}";
|
||||
|
||||
String request = getMentionRequest(subscriptionId, ids, limit, sinceWhen, tagToGet);
|
||||
sendRequest(relayUrl, request);
|
||||
@ -118,7 +119,7 @@ class Relays {
|
||||
|
||||
void getIdAndMentionEvents(String relayUrl, Set<String> ids, int limit, int idSinceWhen, int mentionSinceWhen, String tagToGet, String idType) {
|
||||
|
||||
String subscriptionId = "id_mention_tag" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6);
|
||||
String subscriptionId = "id_mention_tag${relays[relayUrl]?.numRequestsSent??""}_${relayUrl.substring(6)}";
|
||||
String request = getIdAndMentionRequest(subscriptionId, ids, limit, idSinceWhen, mentionSinceWhen, tagToGet, idType);
|
||||
sendRequest(relayUrl, request);
|
||||
}
|
||||
@ -128,7 +129,7 @@ class Relays {
|
||||
* @connect Connect to given relay and get all events for multiple users/publicKey and insert the
|
||||
* received events in the given List<Event>
|
||||
*/
|
||||
void getMultiUserEvents(String relayUrl, List<String> publicKeys, int limit, int sinceWhen, [Set<int>? kind = null]) {
|
||||
void getMultiUserEvents(String relayUrl, List<String> publicKeys, int limit, int sinceWhen, [Set<int>? kind]) {
|
||||
Set<String> setPublicKeys = publicKeys.toSet();
|
||||
|
||||
if( relays.containsKey(relayUrl)) {
|
||||
@ -139,7 +140,7 @@ class Relays {
|
||||
}
|
||||
}
|
||||
|
||||
String subscriptionId = "multiple_user" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6);
|
||||
String subscriptionId = "multiple_user${relays[relayUrl]?.numRequestsSent??""}_${relayUrl.substring(6)}";
|
||||
String request = getMultiUserRequest( subscriptionId, setPublicKeys, limit, sinceWhen, kind);
|
||||
sendRequest(relayUrl, request);
|
||||
}
|
||||
@ -215,7 +216,7 @@ class Relays {
|
||||
print('WebSocketChannelException exception for relay $relayUrl');
|
||||
return; // is presently not used/called
|
||||
}
|
||||
on Exception catch(ex) {
|
||||
on Exception {
|
||||
printWarning("Invalid event\n");
|
||||
}
|
||||
|
||||
@ -261,9 +262,9 @@ void getContactFeed(Set<String> relayUrls, Set<String> setContacts, int numEvent
|
||||
groupContacts.add(contacts[i + j]);
|
||||
}
|
||||
|
||||
relayUrls.forEach((relayUrl) {
|
||||
for (var relayUrl in relayUrls) {
|
||||
relays.getMultiUserEvents(relayUrl, groupContacts, numEventsToGet, sinceWhen);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -272,28 +273,28 @@ void getContactFeed(Set<String> relayUrls, Set<String> setContacts, int numEvent
|
||||
}
|
||||
|
||||
void getUserEvents(Set<String> serverUrls, String publicKey, int numUserEvents, int sinceWhen) {
|
||||
serverUrls.forEach((serverUrl) {
|
||||
for (var serverUrl in serverUrls) {
|
||||
relays.getUserEvents(serverUrl, publicKey, numUserEvents, sinceWhen);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void getMentionEvents(Set<String> serverUrls, Set<String> ids, int numUserEvents, int sinceWhen, String tagToGet) {
|
||||
serverUrls.forEach((serverUrl) {
|
||||
for (var serverUrl in serverUrls) {
|
||||
relays.getMentionEvents(serverUrl, ids, numUserEvents, sinceWhen, tagToGet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void getIdAndMentionEvents(Set<String> serverUrls, Set<String> ids, int numUserEvents, int idSinceWhen, int mentionSinceWhen, String tagToGet, String idType) {
|
||||
serverUrls.forEach((serverUrl) {
|
||||
for (var serverUrl in serverUrls) {
|
||||
relays.getIdAndMentionEvents(serverUrl, ids, numUserEvents, idSinceWhen, mentionSinceWhen, tagToGet, idType);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getKindEvents(List<int> kind, Set<String> serverUrls, int limit, int sinceWhen) {
|
||||
serverUrls.forEach((serverUrl) {
|
||||
for (var serverUrl in serverUrls) {
|
||||
relays.getKindEvents(kind, serverUrl, limit, sinceWhen);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void getMultiUserEvents(Set<String> serverUrls, Set<String> setPublicKeys, int numUserEvents, int sinceWhen, [Set<int>? kind]) {
|
||||
@ -314,23 +315,24 @@ void getMultiUserEvents(Set<String> serverUrls, Set<String> setPublicKeys, int n
|
||||
|
||||
// send request for specific events whose id's are passed as list eventIds
|
||||
void sendEventsRequest(Set<String> serverUrls, Set<String> eventIds) {
|
||||
if( eventIds.length == 0)
|
||||
if( eventIds.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
String eventIdsStr = getCommaSeparatedQuotedStrs(eventIds);;
|
||||
String eventIdsStr = getCommaSeparatedQuotedStrs(eventIds);
|
||||
|
||||
String getEventRequest = '["REQ","event_${eventIds.length}",{"ids":[$eventIdsStr]}]';
|
||||
if( gDebug > 0) log.info("sending $getEventRequest");
|
||||
|
||||
serverUrls.forEach((url) {
|
||||
for (var url in serverUrls) {
|
||||
relays.sendRequest(url, getEventRequest);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void sendRequest(Set<String> serverUrls, request) {
|
||||
serverUrls.forEach((url) {
|
||||
for (var url in serverUrls) {
|
||||
relays.sendRequest(url, request);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Set<Event> getRecievedEvents() {
|
||||
@ -343,7 +345,7 @@ void clearEvents() {
|
||||
}
|
||||
|
||||
void setRelaysIntialEvents(Set<Event> eventsFromFile) {
|
||||
eventsFromFile.forEach((element) {relays.uniqueIdsRecieved.add(element.eventData.id);});
|
||||
for (var element in eventsFromFile) {relays.uniqueIdsRecieved.add(element.eventData.id);}
|
||||
relays.rEvents = eventsFromFile;
|
||||
}
|
||||
|
||||
|
@ -241,8 +241,9 @@ Map<String, String> pubkeyColor = { '0': magentaColor, '1': brightMagentaColor,
|
||||
};
|
||||
|
||||
String getNameColor( String pubkey) {
|
||||
if( pubkey.length == 0)
|
||||
if( pubkey.isEmpty) {
|
||||
return brightMagentaColor;
|
||||
}
|
||||
|
||||
String firstChar = pubkey.substring(0, 1).toLowerCase();
|
||||
return pubkeyColor[firstChar]??brightMagentaColor;
|
||||
@ -408,10 +409,11 @@ List<String> lines = intro.split("\n");
|
||||
|
||||
var terminalColumns = gDefaultTextWidth;
|
||||
|
||||
if( stdout.hasTerminal )
|
||||
if( stdout.hasTerminal ) {
|
||||
terminalColumns = stdout.terminalColumns;
|
||||
}
|
||||
|
||||
lines.forEach((line) {print(line.length > terminalColumns ? line.substring(0, terminalColumns) : line );});
|
||||
for (var line in lines) {print(line.length > terminalColumns ? line.substring(0, terminalColumns) : line );}
|
||||
|
||||
}
|
||||
|
||||
@ -427,6 +429,6 @@ void printUsage() {
|
||||
print(gUsage);
|
||||
}
|
||||
void printVersion() {
|
||||
print("$version");
|
||||
print(version);
|
||||
}
|
||||
|
||||
|
271
lib/tree_ds.dart
271
lib/tree_ds.dart
@ -1,4 +1,3 @@
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:nostr_console/event_ds.dart';
|
||||
@ -6,7 +5,7 @@ import 'package:nostr_console/relays.dart';
|
||||
import 'package:nostr_console/utils.dart';
|
||||
import 'package:nostr_console/settings.dart';
|
||||
import 'package:nostr_console/user.dart';
|
||||
import 'dart:math'; // for Point
|
||||
// for Point
|
||||
|
||||
|
||||
typedef fTreeSelector = bool Function(Tree a);
|
||||
@ -16,7 +15,7 @@ typedef fRoomSelector = bool Function(ScrollableMessages room);
|
||||
|
||||
typedef fvisitorMarkNotifications = void Function(Event e);
|
||||
|
||||
Store? gStore = null;
|
||||
Store? gStore;
|
||||
|
||||
// only show in which user is involved
|
||||
bool selectorTrees_selfPosts(Tree t) {
|
||||
@ -37,7 +36,7 @@ bool userInvolved(String pubkey, Event e) {
|
||||
}
|
||||
|
||||
if( gReactions.containsKey(e.eventData.id)) {
|
||||
List<List<String>>? reactors = gReactions[e.eventData.id]??null;
|
||||
List<List<String>>? reactors = gReactions[e.eventData.id];
|
||||
if( reactors != null) {
|
||||
for( var reactor in reactors) {
|
||||
String reactorPubkey = reactor[0];
|
||||
@ -91,7 +90,7 @@ bool followsInvolved(Event e, Event? contactEvent) {
|
||||
|
||||
// check if any of the contact liked it
|
||||
if( gReactions.containsKey(e.eventData.id)) {
|
||||
List<List<String>>? reactors = gReactions[e.eventData.id]??null;
|
||||
List<List<String>>? reactors = gReactions[e.eventData.id];
|
||||
if( reactors != null) {
|
||||
for( var reactor in reactors) {
|
||||
String reactorPubkey = reactor[0];
|
||||
@ -147,20 +146,20 @@ bool showAllRooms (ScrollableMessages room) => selectorShowAllRooms(room);
|
||||
|
||||
int getLatestMessageTime(ScrollableMessages channel) {
|
||||
|
||||
List<String> _messageIds = channel.messageIds;
|
||||
List<String> messageIds = channel.messageIds;
|
||||
if(gStore == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(_messageIds.length == 0) {
|
||||
if(messageIds.isEmpty) {
|
||||
int createdAt = channel.createdAt;
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
int latest = 0;
|
||||
for(int i = 0; i < _messageIds.length; i++) {
|
||||
for(int i = 0; i < messageIds.length; i++) {
|
||||
if( gStore != null) {
|
||||
Tree? tree = (gStore?.allChildEventsMap[_messageIds[i]] );
|
||||
Tree? tree = (gStore?.allChildEventsMap[messageIds[i]] );
|
||||
if( tree != null) {
|
||||
EventData ed = tree.event.eventData;
|
||||
if( ed.createdAt > latest) {
|
||||
@ -193,8 +192,9 @@ DirectMessageRoom? getDirectRoom(List<DirectMessageRoom> rooms, String otherPubk
|
||||
|
||||
int scrollableCompareTo(ScrollableMessages a, ScrollableMessages b) {
|
||||
|
||||
if( gStore == null)
|
||||
if( gStore == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int otherLatest = getLatestMessageTime(b);
|
||||
int thisLatest = getLatestMessageTime(a);
|
||||
@ -228,12 +228,12 @@ class ScrollableMessages {
|
||||
int eventTime = (tempChildEventsMap[messageIds[i]]?.event.eventData.createdAt??0);
|
||||
if( newEventTime < eventTime) {
|
||||
// shift current i and rest one to the right, and put event Time here
|
||||
if(gSpecificDebug > 0 && roomType == enumRoomType.kind140) print("In addMessageToRoom: inserted enc message in middle to room with name ${topHeader}");
|
||||
if(gSpecificDebug > 0 && roomType == enumRoomType.kind140) print("In addMessageToRoom: inserted enc message in middle to room with name $topHeader");
|
||||
messageIds.insert(i, messageId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(gSpecificDebug > 0 && roomType == enumRoomType.kind140) print("In addMessageToRoom: inserted enc message in end of room with name ${topHeader}");
|
||||
if(gSpecificDebug > 0 && roomType == enumRoomType.kind140) print("In addMessageToRoom: inserted enc message in end of room with name $topHeader");
|
||||
|
||||
// insert at end
|
||||
messageIds.add(messageId);
|
||||
@ -273,15 +273,16 @@ class ScrollableMessages {
|
||||
if( messageIds.length > gNumChannelMessagesToShow) {
|
||||
print("\n");
|
||||
printDepth(0);
|
||||
stdout.write("${gNotificationColor}Displayed page number ${page} (out of total $numPages pages, where 1st is the latest 'page').\n");
|
||||
stdout.write("${gNotificationColor}Displayed page number $page (out of total $numPages pages, where 1st is the latest 'page').\n");
|
||||
printDepth(0);
|
||||
stdout.write("To see older pages, enter numbers from 1-${numPages}, in format '/N', a slash followed by the required page number.${gColorEndMarker}\n\n");
|
||||
stdout.write("To see older pages, enter numbers from 1-$numPages, in format '/N', a slash followed by the required page number.$gColorEndMarker\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool selectorNotifications() {
|
||||
if( gStore == null)
|
||||
if( gStore == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < messageIds.length; i++) {
|
||||
Event? e = gStore?.allChildEventsMap[messageIds[i]]?.event;
|
||||
@ -317,6 +318,7 @@ class Channel extends ScrollableMessages {
|
||||
Set<String> participants; // pubkey of all participants - only for encrypted channels
|
||||
String creatorPubkey; // creator of the channel, if event is known
|
||||
|
||||
@override
|
||||
enumRoomType roomType;
|
||||
|
||||
Channel(this.channelId, this.internalChatRoomName, this.about, this.picture, List<String> messageIds, this.participants, this.lastUpdated, this.roomType, [this.creatorPubkey=""] ) :
|
||||
@ -333,7 +335,7 @@ class Channel extends ScrollableMessages {
|
||||
return internalChatRoomName;
|
||||
}
|
||||
|
||||
void set chatRoomName(String newName){
|
||||
set chatRoomName(String newName){
|
||||
internalChatRoomName = newName;
|
||||
super.topHeader = "Channel Name: $newName (Id: $channelId)";
|
||||
}
|
||||
@ -366,11 +368,11 @@ class Channel extends ScrollableMessages {
|
||||
// represents direct chat of kind 4
|
||||
class DirectMessageRoom extends ScrollableMessages{
|
||||
String otherPubkey; // id of user this DM is happening
|
||||
@override
|
||||
int createdAt;
|
||||
|
||||
DirectMessageRoom(this.otherPubkey, List<String> messageIds, this.createdAt):
|
||||
super ( "${(otherPubkey)} ($otherPubkey)", messageIds, createdAt, enumRoomType.kind4) {
|
||||
}
|
||||
super ( "${(otherPubkey)} ($otherPubkey)", messageIds, createdAt, enumRoomType.kind4);
|
||||
|
||||
String getChannelId() {
|
||||
return otherPubkey;
|
||||
@ -404,7 +406,7 @@ class Tree {
|
||||
store = s;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************/
|
||||
/// ********************************************************************************************************************************
|
||||
/* The main print tree function. Calls the reeSelector() for every node and prints it( and its children), only if it returns true.
|
||||
* returns Point , where first int is total Threads ( or top trees) printed, and second is notifications printed
|
||||
* returns list< total top threads printed, total events printed, total notifications printed>
|
||||
@ -412,7 +414,7 @@ class Tree {
|
||||
List<int> printTree(int depth, DateTime newerThan, bool topPost, [int countPrinted = 0, int maxToPrint = gMaxEventsInThreadPrinted]) {
|
||||
List<int> ret = [0,0,0];
|
||||
|
||||
if(event.eventData.isNotification || event.eventData.newLikes.length > 0) {
|
||||
if(event.eventData.isNotification || event.eventData.newLikes.isNotEmpty) {
|
||||
ret[2] = 1;
|
||||
}
|
||||
|
||||
@ -503,7 +505,7 @@ class Tree {
|
||||
if( pubkeys.contains(event.eventData.pubkey) && gReactions.containsKey(event.eventData.id)) {
|
||||
List<List<String>>? reactions = gReactions[event.eventData.id];
|
||||
if( reactions != null) {
|
||||
if( reactions.length > 0) {
|
||||
if( reactions.isNotEmpty) {
|
||||
// set every reaction as a new like so they all get highlighted; these are all later reset after first printing
|
||||
Set<String> reactorPubkeys = getReactorPubkeys(event.eventData.id);
|
||||
event.eventData.newLikes = reactorPubkeys;
|
||||
@ -517,18 +519,20 @@ class Tree {
|
||||
Set<String> pplTagged = pTags.toSet().intersection(pubkeys);
|
||||
|
||||
// 2nd condition: person making the event should not be on this list; they would already be considered in other test
|
||||
if( pplTagged.length > 0 && !pubkeys.contains(event.eventData.pubkey)) {
|
||||
if( pplTagged.isNotEmpty && !pubkeys.contains(event.eventData.pubkey)) {
|
||||
event.eventData.isNotification = isMentioned = true;
|
||||
}
|
||||
|
||||
// check if there are any replies from other people to an event made by someone in list
|
||||
if( pubkeys.contains(event.eventData.pubkey) && children.length > 0) {
|
||||
if( pubkeys.contains(event.eventData.pubkey) && children.isNotEmpty) {
|
||||
for( int i = 0; i < children.length; i++ ) {
|
||||
children.forEach((child) {
|
||||
for (var child in children) {
|
||||
// if child is someone else then set notifications and flag, means there are replies to this event
|
||||
if(child.event.eventData.pubkey != event.eventData.pubkey ) // tests reply is not from same user
|
||||
if(child.event.eventData.pubkey != event.eventData.pubkey ) {
|
||||
// tests reply is not from same user
|
||||
childMatches = child.event.eventData.isNotification = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,8 +601,9 @@ class Tree {
|
||||
if( reactions != null) {
|
||||
for( int i = 0; i < reactions.length; i++) {
|
||||
if( pubkeys.contains(reactions[i][0]) ) {
|
||||
if( enableNotifications)
|
||||
if( enableNotifications) {
|
||||
event.eventData.newLikes.add(reactions[i][0]);
|
||||
}
|
||||
hasReacted = true;
|
||||
}
|
||||
}
|
||||
@ -617,8 +622,9 @@ class Tree {
|
||||
|
||||
// if event is by user(s)
|
||||
if( pubkeys.contains(event.eventData.pubkey)) {
|
||||
if( enableNotifications)
|
||||
if( enableNotifications) {
|
||||
event.eventData.isNotification = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if( hasReacted || childMatches) {
|
||||
@ -636,8 +642,9 @@ class Tree {
|
||||
|
||||
// if event is by user(s)
|
||||
if( pubkeys.contains(event.eventData.pubkey)) {
|
||||
if( enableNotifications)
|
||||
if( enableNotifications) {
|
||||
event.eventData.isNotification = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -721,7 +728,7 @@ class Tree {
|
||||
bool treeSelector_hasNotifications() {
|
||||
|
||||
bool hasNotifications = false;
|
||||
if( event.eventData.isNotification || event.eventData.newLikes.length > 0) {
|
||||
if( event.eventData.isNotification || event.eventData.newLikes.isNotEmpty) {
|
||||
hasNotifications = true;
|
||||
}
|
||||
|
||||
@ -749,7 +756,7 @@ class Tree {
|
||||
count = 1;
|
||||
}
|
||||
|
||||
if( event.eventData.newLikes.length > 0) {
|
||||
if( event.eventData.newLikes.isNotEmpty) {
|
||||
event.eventData.newLikes = {};
|
||||
count = 1;
|
||||
}
|
||||
@ -777,7 +784,7 @@ class Tree {
|
||||
} // end count()
|
||||
} // end Tree
|
||||
|
||||
/***********************************************************************************************************************************/
|
||||
/// ********************************************************************************************************************************
|
||||
/*
|
||||
* The actual tree struture holds only kind 1 events, or only posts. Tree itself can hold any event type( to be fixed, needs renaming etc TODO)
|
||||
* This Store class holds events too in its map, and in its chatRooms structure
|
||||
@ -902,7 +909,7 @@ class Store {
|
||||
static void addTTagEventInChannel(EventData eventData, List<Channel> rooms, Map<String, Tree> tempChildEventsMap) {
|
||||
|
||||
List<String>? tTags = eventData.getTTags();
|
||||
if( tTags != null && tTags.length > 0) {
|
||||
if( tTags != null && tTags.isNotEmpty) {
|
||||
for( int i = 0; i < tTags.length; i++) {
|
||||
String chatRoomId = eventData.getChannelIdForTTagRoom(tTags[i]);
|
||||
Channel? channel = getChannel(rooms, chatRoomId);
|
||||
@ -949,11 +956,9 @@ class Store {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will create a entry in encryptedChannels ( if one does not already exist)
|
||||
* Returns id of channel if one is created, null otherwise.
|
||||
*
|
||||
*/
|
||||
/// Will create a entry in encryptedChannels ( if one does not already exist)
|
||||
/// Returns id of channel if one is created, null otherwise.
|
||||
///
|
||||
static String? createEncryptedRoomFromInvite( List<Channel> encryptedChannels, Map<String, Tree> tempChildEventsMap, Event eventSecretMessage) {
|
||||
|
||||
String? temp140Id = getEncryptedChannelIdFromSecretMessage( eventSecretMessage);
|
||||
@ -969,7 +974,7 @@ class Store {
|
||||
if( event140 != null) {
|
||||
|
||||
Set<String> participants = {};
|
||||
event140.eventData.pTags.forEach((element) { participants.add(element);});
|
||||
for (var element in event140.eventData.pTags) { participants.add(element);}
|
||||
|
||||
String chatRoomId = event140Id;
|
||||
try {
|
||||
@ -1018,7 +1023,7 @@ class Store {
|
||||
|
||||
// update the participant list if the event already exists ( the room was likely creted with 104 invite, which did not have participant list)
|
||||
Set<String> participants = {};
|
||||
event14x.eventData.pTags.forEach((element) { participants.add(element);});
|
||||
for (var element in event14x.eventData.pTags) { participants.add(element);}
|
||||
Channel? channel = getChannel(encryptedChannels, event14x.eventData.id);
|
||||
|
||||
dynamic json = jsonDecode(event14x.eventData.content);
|
||||
@ -1042,7 +1047,7 @@ class Store {
|
||||
|
||||
case 141:
|
||||
Set<String> participants = {};
|
||||
event14x.eventData.pTags.forEach((element) { participants.add(element);});
|
||||
for (var element in event14x.eventData.pTags) { participants.add(element);}
|
||||
|
||||
String chatRoomId = event14x.eventData.getChannelIdForKind4x();
|
||||
if( chatRoomId.length != 64) {
|
||||
@ -1093,7 +1098,7 @@ class Store {
|
||||
}
|
||||
} else {
|
||||
// could not get channel id of message.
|
||||
printWarning("---Could not get encryptd channel for message id ${event14x.eventData.id} got channelId : ${channelId} its len ${channelId.length}");
|
||||
printWarning("---Could not get encryptd channel for message id ${event14x.eventData.id} got channelId : $channelId its len ${channelId.length}");
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1158,7 +1163,7 @@ class Store {
|
||||
directRooms.add( newDirectRoom);
|
||||
if( ce.eventData.id == gCheckEventId && gDebug >= 0) print("Adding new message ${ce.eventData.id} to NEW direct room $directRoomId. sender pubkey = ${ce.eventData.pubkey}.");
|
||||
}
|
||||
if( ce.eventData.evaluatedContent.length > 0) numMessagesDecrypted++;
|
||||
if( ce.eventData.evaluatedContent.isNotEmpty) numMessagesDecrypted++;
|
||||
} else {
|
||||
if( gDebug > 0) print("Could not get chat room id for event ${ce.eventData.id} sender pubkey = ${ce.eventData.pubkey}.");
|
||||
}
|
||||
@ -1252,7 +1257,7 @@ class Store {
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************/
|
||||
/// ********************************************************************************************************************************
|
||||
// @method create top level Tree from events.
|
||||
// first create a map. then process each element in the map by adding it to its parent ( if its a child tree)
|
||||
factory Store.fromEvents(Set<Event> events) {
|
||||
@ -1264,12 +1269,12 @@ class Store {
|
||||
|
||||
// create a map tempChildEventsMap from list of events, key is eventId and value is event itself
|
||||
Map<String, Tree> tempChildEventsMap = {};
|
||||
events.forEach((event) {
|
||||
for (var event in events) {
|
||||
// only add in map those kinds that are supported or supposed to be added ( 0 1 3 7 40)
|
||||
if( typesInEventMap.contains(event.eventData.kind)) {
|
||||
tempChildEventsMap[event.eventData.id] = Tree.withoutStore( event, []);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processDeleteEvents(tempChildEventsMap); // handle returned values perhaps later
|
||||
processReactions(events, tempChildEventsMap);
|
||||
@ -1322,7 +1327,7 @@ class Store {
|
||||
}
|
||||
|
||||
// if reacted to event is not in store, then add it to dummy list so it can be fetched
|
||||
if( tree.event.eventData.eTags.length > 0 && tree.event.eventData.eTags.last.length > 0) {
|
||||
if( tree.event.eventData.eTags.isNotEmpty && tree.event.eventData.eTags.last.isNotEmpty) {
|
||||
String reactedToId = tree.event.eventData.eTags.last[0];
|
||||
if( !tempChildEventsMap.containsKey(reactedToId) && tree.event.eventData.createdAt > getSecondsDaysAgo(3)) {
|
||||
//print("liked event not found in store.");
|
||||
@ -1353,7 +1358,7 @@ class Store {
|
||||
// allEncryptedGroupInviteIds has been created above
|
||||
// now create encrypted rooms from that list which are just for the current user
|
||||
Set<String> usersEncryptedChannelIds = {};
|
||||
allEncryptedGroupInviteIds.forEach((secretEventId) {
|
||||
for (var secretEventId in allEncryptedGroupInviteIds) {
|
||||
Event? secretEvent = tempChildEventsMap[secretEventId]?.event;
|
||||
|
||||
if( secretEvent != null) {
|
||||
@ -1363,7 +1368,7 @@ class Store {
|
||||
usersEncryptedChannelIds.add(newEncryptedChannelId); // is later used so a request can be sent to fetch events related to this room
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tempChildEventsMap.forEach((newEventId, tree) {
|
||||
int eKind = tree.event.eventData.kind;
|
||||
@ -1391,7 +1396,7 @@ class Store {
|
||||
return Store( topLevelTrees, tempChildEventsMap, tempWithoutParent, channels, encryptedChannels, tempDirectRooms, allEncryptedGroupInviteIds);
|
||||
} // end fromEvents()
|
||||
|
||||
/***********************************************************************************************************************************/
|
||||
/// ********************************************************************************************************************************
|
||||
/* @processIncomingEvent inserts the relevant events into the tree and otherwise processes likes, delete events etc.
|
||||
* returns the id of the ones actually new so that they can be printed as notifications.
|
||||
*/
|
||||
@ -1403,26 +1408,26 @@ class Store {
|
||||
Set<String> dummyEventIds = {};
|
||||
|
||||
// add the event to the main event store thats allChildEventsMap
|
||||
newEventsToProcess.forEach((newEvent) {
|
||||
for (var newEvent in newEventsToProcess) {
|
||||
|
||||
if( newEvent.eventData.kind == 1 && newEvent.eventData.content.compareTo("Hello Nostr! :)") == 0 && newEvent.eventData.id.substring(0,3).compareTo("000") == 0) {
|
||||
return; // spam prevention
|
||||
continue; // spam prevention
|
||||
}
|
||||
|
||||
if( allChildEventsMap.containsKey(newEvent.eventData.id)) {// don't process if the event is already present in the map
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
//ignore bots
|
||||
if( [4, 42, 142].contains( newEvent.eventData.kind ) && gBots.contains(newEvent.eventData.pubkey)) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle reaction events and return if we could not find the reacted to. Continue otherwise to add this to notification set newEventIdsSet
|
||||
if( newEvent.eventData.kind == 7) {
|
||||
if( processReaction(newEvent, allChildEventsMap) == "") {
|
||||
if(gDebug > 0) print("In insertEvents: For new reaction ${newEvent.eventData.id} could not find reactedTo or reaction was already present by this reactor");
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1430,12 +1435,12 @@ class Store {
|
||||
if( newEvent.eventData.kind == 5) {
|
||||
processDeleteEvent(allChildEventsMap, newEvent);
|
||||
if(gDebug > 0) print("In insertEvents: For new deleteion event ${newEvent.eventData.id} could not process it.");
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( newEvent.eventData.kind == 4) {
|
||||
if( !isValidDirectMessage(newEvent.eventData)) { // direct message not relevant to user are ignored; also otherwise validates the message that it has one p tag
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1445,12 +1450,13 @@ class Store {
|
||||
|
||||
// only kind 0, 1, 3, 4, 5( delete), 7, 40, 42, 140, 142 events are added to map-store, return otherwise
|
||||
if( !typesInEventMap.contains(newEvent.eventData.kind) ) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// expand mentions ( and translate if flag is set) and then add event to main event map; 142 events are expanded later
|
||||
if( newEvent.eventData.kind != 142)
|
||||
if( newEvent.eventData.kind != 142) {
|
||||
newEvent.eventData.translateAndExpandMentions( allChildEventsMap); // this also handles dm decryption for kind 4 messages, for kind 1 will do translation/expansion;
|
||||
}
|
||||
|
||||
// add them to the main store of the Tree object, but after checking that its not one of the dummy/missing events.
|
||||
// In that case, replace the older dummy event, and only then add it to store-map
|
||||
@ -1462,7 +1468,7 @@ class Store {
|
||||
if( gDebug >= 0 && newEvent.eventData.id == gCheckEventId) log.info("In processIncoming: Replaced old dummy event of id: ${newEvent.eventData.id}");
|
||||
tree.event = newEvent;
|
||||
allChildEventsMap[tree.event.eventData.id] = tree;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1471,10 +1477,10 @@ class Store {
|
||||
// add to new-notification list only if this is a recent event ( because relays may send old events, and we dont want to highlight stale messages)
|
||||
newEventIdsSet.add(newEvent.eventData.id);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// now go over the newly inserted event, and add it to the tree for kind 1 events, add 42 events to channels. rest ( such as kind 0, kind 3, kind 7) are ignored.
|
||||
newEventIdsSet.forEach((newId) {
|
||||
for (var newId in newEventIdsSet) {
|
||||
Tree? newTree = allChildEventsMap[newId];
|
||||
if( newTree != null) { // this should return true because we just inserted this event in the allEvents in block above
|
||||
|
||||
@ -1497,21 +1503,22 @@ class Store {
|
||||
topPosts.add(dummyTopNode);
|
||||
|
||||
// add it to list to fetch it from relays
|
||||
if( parentId.length == 64)
|
||||
dummyEventIds.add(parentId);
|
||||
if( parentId.length == 64) {
|
||||
dummyEventIds.add(parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now process case where there is a tag which should put this kind 1 message in a channel
|
||||
String? location = newTree.event.eventData.getSpecificTag("location");
|
||||
if( location != null && location != "") {
|
||||
addLocationTagEventInChannel(newTree.event.eventData, this.channels, allChildEventsMap);
|
||||
addLocationTagEventInChannel(newTree.event.eventData, channels, allChildEventsMap);
|
||||
}
|
||||
|
||||
// now process case where there is a tag which should put this kind 1 message in a channel
|
||||
List<String>? tTags = newTree.event.eventData.getTTags();
|
||||
if( tTags != null && tTags != "") {
|
||||
addTTagEventInChannel(newTree.event.eventData, this.channels, allChildEventsMap);
|
||||
addTTagEventInChannel(newTree.event.eventData, channels, allChildEventsMap);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1562,19 +1569,19 @@ class Store {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// get dummy events
|
||||
sendEventsRequest(gListRelayUrls, dummyEventIds);
|
||||
|
||||
int totalTreeSize = 0;
|
||||
topPosts.forEach((element) {totalTreeSize += element.count();});
|
||||
for (var element in topPosts) {totalTreeSize += element.count();}
|
||||
if(gDebug > 0) print("In end of insertEvents: allChildEventsMap size = ${allChildEventsMap.length}; mainTree count = $totalTreeSize");
|
||||
if(gDebug > 0) print("Returning ${newEventIdsSet.length} new notification-type events, which are ${newEventIdsSet.length < 10 ? newEventIdsSet: " <had more than 10 elements>"} ");
|
||||
return newEventIdsSet;
|
||||
} // end insertEvents()
|
||||
|
||||
/***********************************************************************************************************************************/
|
||||
/// ********************************************************************************************************************************
|
||||
/*
|
||||
* @printNotifications Add the given events to the Tree, and print the events as notifications
|
||||
* It should be ensured that these are only kind 1 events
|
||||
@ -1600,13 +1607,13 @@ class Store {
|
||||
}
|
||||
|
||||
List<Tree> topNotificationTree = []; // collect all top tress to display in this list. only unique tress will be displayed
|
||||
newEventIdsSet.forEach((eventID) {
|
||||
for (var eventID in newEventIdsSet) {
|
||||
|
||||
Tree ?t = allChildEventsMap[eventID];
|
||||
if( t == null) {
|
||||
// ignore if not in Tree. Should ideally not happen. TODO write warning otherwise
|
||||
if( gDebug > 0) print("In printNotifications: Could not find event $eventID in tree");
|
||||
return;
|
||||
continue;
|
||||
} else {
|
||||
if( isRelevantForNotification(t)) {
|
||||
switch(t.event.eventData.kind) {
|
||||
@ -1643,7 +1650,7 @@ class Store {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// remove duplicate top trees
|
||||
Set ids = {};
|
||||
@ -1655,7 +1662,7 @@ class Store {
|
||||
gFollowList = getFollows(userPublicKey);
|
||||
|
||||
List<int> ret = [0,0,0];
|
||||
topNotificationTree.forEach( (t) {
|
||||
for (var t in topNotificationTree) {
|
||||
bool selectorTrees_followActionsWithNotifications (Tree t) => t.treeSelectorUserPostAndLike(getFollows( userPublicKey), enableNotifications: true);
|
||||
if( selectorTrees_followActionsWithNotifications(t)) {
|
||||
List<int> temp = Store.printTopPost(t, 0, DateTime(0));
|
||||
@ -1664,7 +1671,7 @@ class Store {
|
||||
ret[2] += temp[2];
|
||||
//print("\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1691,7 +1698,7 @@ class Store {
|
||||
return count;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************/
|
||||
/// ********************************************************************************************************************************
|
||||
/* The main print tree function. Calls the treeSelector() for every node and prints it( and its children), only if it returns true.
|
||||
*/
|
||||
List<int> printStoreTrees(int depth, DateTime newerThan, fTreeSelector treeSelector, [int maxToPrint = gMaxEventsInThreadPrinted]) {
|
||||
@ -1787,11 +1794,9 @@ class Store {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @printAllChennelsInfo Print one line information about all channels, which are type 40 events ( class ChatRoom) and for 14x channels both; channelsToPrint is different for both
|
||||
*
|
||||
* @param numRoomsOverview This many number of rooms should be printed.
|
||||
*/
|
||||
/// @printAllChennelsInfo Print one line information about all channels, which are type 40 events ( class ChatRoom) and for 14x channels both; channelsToPrint is different for both
|
||||
///
|
||||
/// @param numRoomsOverview This many number of rooms should be printed.
|
||||
int printChannelsOverview(List<Channel> channelsToPrint, int numRoomsOverview, fRoomSelector selector, var tempChildEventsMap , Set<String>? secretMessageIds) {
|
||||
|
||||
channelsToPrint.sort(scrollableCompareTo);
|
||||
@ -1818,7 +1823,7 @@ class Store {
|
||||
|
||||
//stdout.write("channel type: " + channelsToPrint[j].roomType.toString());
|
||||
|
||||
if( channelsToPrint[j].participants.length > 0 && !channelsToPrint[j].participants.contains(userPublicKey)) {
|
||||
if( channelsToPrint[j].participants.isNotEmpty && !channelsToPrint[j].participants.contains(userPublicKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1838,11 +1843,11 @@ class Store {
|
||||
}
|
||||
|
||||
if( channelsToPrint[j].chatRoomName != "") {
|
||||
name = "${channelsToPrint[j].chatRoomName}";
|
||||
name = channelsToPrint[j].chatRoomName;
|
||||
}
|
||||
|
||||
int numMessages = channelsToPrint[j].getNumValidMessages();
|
||||
stdout.write("${name} ${getNumSpaces(32-name.length)} $id $numMessages${getNumSpaces(20- numMessages.toString().length)}");
|
||||
stdout.write("$name ${getNumSpaces(32-name.length)} $id $numMessages${getNumSpaces(20- numMessages.toString().length)}");
|
||||
numChannelsActuallyPrinted++;
|
||||
List<String> messageIds = channelsToPrint[j].messageIds;
|
||||
for( int i = messageIds.length - 1; i >= 0; i--) {
|
||||
@ -1850,7 +1855,7 @@ class Store {
|
||||
Event? e = allChildEventsMap[messageIds[i]]?.event;
|
||||
if( e!= null) {
|
||||
if( !(e.eventData.kind == 142 && e.eventData.content == e.eventData.evaluatedContent)) {
|
||||
stdout.write("${e.eventData.getAsLine(tempChildEventsMap, secretMessageIds, channelsToPrint)}");
|
||||
stdout.write(e.eventData.getAsLine(tempChildEventsMap, secretMessageIds, channelsToPrint));
|
||||
break; // print only one event, the latest one
|
||||
}
|
||||
}
|
||||
@ -1886,15 +1891,15 @@ class Store {
|
||||
stdout.write("\nChannel participants : ");
|
||||
|
||||
int i = 0;
|
||||
room.participants.forEach((participant) {
|
||||
for (var participant in room.participants) {
|
||||
|
||||
if( i != 0) {
|
||||
stdout.write(', ');
|
||||
}
|
||||
String pName = getAuthorName(participant);
|
||||
printInColor("$pName", gCommentColor);
|
||||
printInColor(pName, gCommentColor);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1968,7 +1973,7 @@ class Store {
|
||||
}
|
||||
return fullChannelId.first;
|
||||
} else {
|
||||
if( fullChannelId.length == 0) {
|
||||
if( fullChannelId.isEmpty) {
|
||||
printWarning("Could not find the channel.");
|
||||
}
|
||||
else {
|
||||
@ -1982,16 +1987,15 @@ class Store {
|
||||
return directRooms.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @printDirectRoomInfo Print one line information about chat rooms
|
||||
*/
|
||||
/// @printDirectRoomInfo Print one line information about chat rooms
|
||||
int printDirectRoomsOverview(fRoomSelector roomSelector, int numRoomsOverview, var tempChildEventsMap) {
|
||||
directRooms.sort(scrollableCompareTo);
|
||||
|
||||
int numNotificationRooms = 0;
|
||||
for( int j = 0; j < directRooms.length; j++) {
|
||||
if( roomSelector(directRooms[j]))
|
||||
if( roomSelector(directRooms[j])) {
|
||||
numNotificationRooms++;
|
||||
}
|
||||
}
|
||||
|
||||
// even if num rooms is zero, we will show the heading when its show all rooms
|
||||
@ -2026,8 +2030,9 @@ class Store {
|
||||
|
||||
int iNotification = 0; // notification counter
|
||||
for( int j = startRoomIndex; j < endRoomIndex; j++) {
|
||||
if( !roomSelector(directRooms[j]))
|
||||
if( !roomSelector(directRooms[j])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// print only that we have been asked for
|
||||
if( iNotification++ > numNotificationRooms) {
|
||||
@ -2042,7 +2047,7 @@ class Store {
|
||||
room.visitAllMessages(this, markAllRead);
|
||||
|
||||
int numMessages = room.messageIds.length;
|
||||
stdout.write("${name} ${getNumSpaces(32-name.length)} $id $numMessages${getNumSpaces(18- numMessages.toString().length)}");
|
||||
stdout.write("$name ${getNumSpaces(32-name.length)} $id $numMessages${getNumSpaces(18- numMessages.toString().length)}");
|
||||
|
||||
// print latest event in one line
|
||||
List<String> messageIds = room.messageIds;
|
||||
@ -2106,10 +2111,10 @@ class Store {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if( lookedUpName.length > 0) {
|
||||
if( lookedUpName.isNotEmpty) {
|
||||
printWarning("Got more than one public id for the name given, which are: ");
|
||||
for(String pubkey in lookedUpName) {
|
||||
print("${getAuthorName(pubkey)} - ${pubkey}, ");
|
||||
print("${getAuthorName(pubkey)} - $pubkey, ");
|
||||
}
|
||||
}
|
||||
else { // in case the given id is not present in our global list of usernames, create new room for them
|
||||
@ -2169,7 +2174,7 @@ class Store {
|
||||
Future<void> writeEventsToFile(String filename) async {
|
||||
|
||||
// this variable will be used later; update it if needed
|
||||
if( gFollowList.length == 0) {
|
||||
if( gFollowList.isEmpty) {
|
||||
gFollowList = getFollows(userPublicKey);
|
||||
}
|
||||
|
||||
@ -2207,7 +2212,7 @@ class Store {
|
||||
}
|
||||
|
||||
String temp = tree.event.originalJson.trim();
|
||||
String line = "${temp}\n";
|
||||
String line = "$temp\n";
|
||||
nLinesStr += line;
|
||||
eventCounter++;
|
||||
if( tree.event.eventData.kind == 1) {
|
||||
@ -2227,8 +2232,8 @@ class Store {
|
||||
nLinesStr = "";
|
||||
}
|
||||
|
||||
if(gDebug > 0) log.info("finished writing eventCounter = ${eventCounter}.");
|
||||
print("Appended $eventCounter new events to file \"$gEventsFilename\" of which ${countPosts} are posts.");
|
||||
if(gDebug > 0) log.info("finished writing eventCounter = $eventCounter.");
|
||||
print("Appended $eventCounter new events to file \"$gEventsFilename\" of which $countPosts are posts.");
|
||||
} on Exception catch (e) {
|
||||
print("Could not open file $filename.");
|
||||
if( gDebug > 0) print("Could not open file: $e");
|
||||
@ -2241,7 +2246,7 @@ class Store {
|
||||
* Also adds 'client' tag with application name.
|
||||
* @parameter replyToId First few letters of an event id for which reply is being made
|
||||
*/
|
||||
String getTagStr(String replyToId, String clientName, [bool addAllP = false, Set<String>? extraTags = null]) {
|
||||
String getTagStr(String replyToId, String clientName, [bool addAllP = false, Set<String>? extraTags]) {
|
||||
clientName = (clientName == "")? "nostr_console": clientName; // in case its empty
|
||||
|
||||
//print("extraTags = $extraTags");
|
||||
@ -2249,26 +2254,29 @@ class Store {
|
||||
|
||||
if( extraTags != null)
|
||||
for( String extraTag in extraTags) {
|
||||
if( otherTags.length > 0)
|
||||
if( otherTags.isNotEmpty) {
|
||||
otherTags += ",";
|
||||
}
|
||||
otherTags += '["t","$extraTag"]';
|
||||
}
|
||||
|
||||
if( gWhetherToSendClientTag) {
|
||||
if( otherTags.length > 0)
|
||||
if( otherTags.isNotEmpty) {
|
||||
otherTags += ",";
|
||||
}
|
||||
otherTags += '["client","$clientName"]';
|
||||
}
|
||||
|
||||
if( gUserLocation != "") {
|
||||
if( otherTags.length > 0)
|
||||
if( otherTags.isNotEmpty) {
|
||||
otherTags += ",";
|
||||
}
|
||||
otherTags += '["location","$gUserLocation"]';
|
||||
}
|
||||
|
||||
//print("otherTags = $otherTags");
|
||||
if( replyToId.isEmpty) {
|
||||
return otherTags.length >0 ? otherTags: '[]';
|
||||
return otherTags.isNotEmpty ? otherTags: '[]';
|
||||
}
|
||||
|
||||
String strTags = otherTags ;
|
||||
@ -2293,7 +2301,7 @@ class Store {
|
||||
if( latestEventId.isEmpty && replyToId.length == 64) {
|
||||
latestEventId = replyToId;
|
||||
}
|
||||
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.length != 0) {
|
||||
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.isNotEmpty) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -2301,8 +2309,9 @@ class Store {
|
||||
if( latestEventId.isNotEmpty) {
|
||||
String? pTagPubkey = allChildEventsMap[latestEventId]?.event.eventData.pubkey;
|
||||
if( pTagPubkey != null) {
|
||||
if( strTags.length > 0)
|
||||
if( strTags.isNotEmpty) {
|
||||
strTags += ",";
|
||||
}
|
||||
strTags += '["p","$pTagPubkey"]';
|
||||
}
|
||||
String relay = getRelayOfUser(userPublicKey, pTagPubkey??"");
|
||||
@ -2315,14 +2324,16 @@ class Store {
|
||||
Tree topTree = getTopTree(t);
|
||||
rootEventId = topTree.event.eventData.id;
|
||||
if( rootEventId != latestEventId) { // if the reply is to a top/parent event, then only one e tag is sufficient
|
||||
if( strTags.length > 0)
|
||||
if( strTags.isNotEmpty) {
|
||||
strTags += ",";
|
||||
}
|
||||
strTags += '["e","$rootEventId","","root"]';
|
||||
}
|
||||
}
|
||||
|
||||
if( strTags.length > 0)
|
||||
if( strTags.isNotEmpty) {
|
||||
strTags += ",";
|
||||
}
|
||||
strTags += '["e","$latestEventId","$relay","reply"]';
|
||||
}
|
||||
|
||||
@ -2405,7 +2416,7 @@ class Store {
|
||||
latestEventId = replyToId;
|
||||
}
|
||||
|
||||
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.length != 0) {
|
||||
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.isNotEmpty) {
|
||||
printWarning('Could not find the given id: $replyToId. Sending a regular message.');
|
||||
}
|
||||
|
||||
@ -2422,7 +2433,7 @@ class Store {
|
||||
|
||||
// add root for kind 1 in rooms
|
||||
if( [enumRoomType.RoomLocationTag, enumRoomType.RoomTTag].contains( channel.roomType) ) {
|
||||
Tree? replyTree = allChildEventsMap[latestEventId]??null;
|
||||
Tree? replyTree = allChildEventsMap[latestEventId];
|
||||
if( replyTree != null) {
|
||||
Tree rootTree = getTopTree(replyTree);
|
||||
String rootEventId = rootTree.event.eventData.id;
|
||||
@ -2517,7 +2528,7 @@ class Store {
|
||||
} else {
|
||||
stdout.write("* Of the $selfNumContacts people you follow, $numSecond follow you back. Their names are: ");
|
||||
mutualFollows.sort();
|
||||
mutualFollows.forEach((name) { stdout.write("$name, ");});
|
||||
for (var name in mutualFollows) { stdout.write("$name, ");}
|
||||
}
|
||||
print("");
|
||||
} else { // end if contact event was found
|
||||
@ -2536,9 +2547,9 @@ class Store {
|
||||
static List<String> processDeleteEvent(Map<String, Tree> tempChildEventsMap, Event deleterEvent) {
|
||||
List<String> deletedEventIds = [];
|
||||
if( deleterEvent.eventData.kind == 5) {
|
||||
deleterEvent.eventData.tags.forEach((tag) {
|
||||
for (var tag in deleterEvent.eventData.tags) {
|
||||
if( tag.length < 2) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if( tag[0] == "e") {
|
||||
String deletedEventId = tag[1];
|
||||
@ -2555,7 +2566,7 @@ class Store {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} // end if
|
||||
return deletedEventIds;
|
||||
} // end processDeleteEvent
|
||||
@ -2566,7 +2577,7 @@ class Store {
|
||||
Event deleterEvent = tree.event;
|
||||
if( deleterEvent.eventData.kind == 5) {
|
||||
List<String> tempIds = processDeleteEvent(tempChildEventsMap, deleterEvent);
|
||||
tempIds.forEach((tempId) { deletedEventIds.add(tempId); });
|
||||
for (var tempId in tempIds) { deletedEventIds.add(tempId); }
|
||||
}
|
||||
});
|
||||
return deletedEventIds;
|
||||
@ -2590,8 +2601,9 @@ class Store {
|
||||
// the reactedTo event's id, blank if invalid reaction etc
|
||||
static String processReaction(Event event, Map<String, Tree> tempChildEventsMap) {
|
||||
|
||||
if( gDebug > 0 && event.eventData.id == gCheckEventId)
|
||||
print("in processReaction: 0 got reaction $gCheckEventId");
|
||||
if( gDebug > 0 && event.eventData.id == gCheckEventId) {
|
||||
print("in processReaction: 0 got reaction $gCheckEventId");
|
||||
}
|
||||
|
||||
List<String> validReactionList = ["+", "!"]; // TODO support opposite reactions
|
||||
List<String> opppositeReactions = ['-', "~"];
|
||||
@ -2785,20 +2797,24 @@ Store getTree(Set<Event> events) {
|
||||
events.retainWhere((event) => ids.add(event.eventData.id));
|
||||
|
||||
// process kind 0 events about metadata
|
||||
events.forEach( (event) => processKind0Event(event));
|
||||
for (var event in events) {
|
||||
processKind0Event(event);
|
||||
}
|
||||
|
||||
// process kind 3 events which is contact list. Update global info about the user (with meta data)
|
||||
events.forEach( (event) => processKind3Event(event));
|
||||
for (var event in events) {
|
||||
processKind3Event(event);
|
||||
}
|
||||
|
||||
// create tree from events
|
||||
Store node = Store.fromEvents(events);
|
||||
|
||||
// translate and expand mentions
|
||||
events.where((element) => [1, 42].contains(element.eventData.kind)).forEach( (event) => event.eventData.translateAndExpandMentions( node.allChildEventsMap));;
|
||||
events.where((element) => [1, 42].contains(element.eventData.kind)).forEach( (event) => event.eventData.translateAndExpandMentions( node.allChildEventsMap));
|
||||
|
||||
// has been done in fromEvents
|
||||
//events.where((element) => [gSecretMessageKind].contains(element.eventData.kind)).forEach( (event) => event.eventData.TranslateAndDecryptGroupInvite( ));;
|
||||
events.where((element) => element.eventData.kind == 142).forEach( (event) => event.eventData.translateAndDecrypt14x(node.encryptedGroupInviteIds, node.encryptedChannels, node.allChildEventsMap));;
|
||||
events.where((element) => element.eventData.kind == 142).forEach( (event) => event.eventData.translateAndDecrypt14x(node.encryptedGroupInviteIds, node.encryptedChannels, node.allChildEventsMap));
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -2807,18 +2823,19 @@ Store getTree(Set<Event> events) {
|
||||
String getDirectRoomId(EventData eventData) {
|
||||
|
||||
List<String> participantIds = [];
|
||||
eventData.tags.forEach((tag) {
|
||||
if( tag.length < 2)
|
||||
return;
|
||||
for (var tag in eventData.tags) {
|
||||
if( tag.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if( tag[0] == 'p') {
|
||||
participantIds.add(tag[1]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
participantIds.sort();
|
||||
String uniqueId = "";
|
||||
participantIds.forEach((element) {uniqueId += element;}); // TODO ensure its only one thats added s
|
||||
for (var element in participantIds) {uniqueId += element;} // TODO ensure its only one thats added s
|
||||
|
||||
// send the other persons pubkey as identifier
|
||||
if( eventData.pubkey == userPublicKey) {
|
||||
|
@ -10,7 +10,7 @@ Event? getContactEvent(String pubkey) {
|
||||
|
||||
// get the latest kind 3 event for the user, which lists his 'follows' list
|
||||
if( gKindONames.containsKey(pubkey)) {
|
||||
Event? e = (gKindONames[pubkey]?.latestContactEvent)??null;
|
||||
Event? e = (gKindONames[pubkey]?.latestContactEvent);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -23,7 +23,9 @@ Set<String> getFollows(String pubkey) {
|
||||
|
||||
Event? profileContactEvent = getContactEvent(pubkey);
|
||||
if( profileContactEvent != null) {
|
||||
profileContactEvent.eventData.contactList.forEach((x) => followPubkeys.add(x.contactPubkey));
|
||||
for (var x in profileContactEvent.eventData.contactList) {
|
||||
followPubkeys.add(x.contactPubkey);
|
||||
}
|
||||
//followPubkeys = profileContactEvent.eventData.contactList.toSet();
|
||||
}
|
||||
|
||||
@ -33,7 +35,7 @@ Set<String> getFollows(String pubkey) {
|
||||
Set<String> getUserChannels(Set<Event> userEvents, String userPublicKey) {
|
||||
Set<String> userChannels = {};
|
||||
|
||||
userEvents.forEach((event) {
|
||||
for (var event in userEvents) {
|
||||
if( event.eventData.pubkey == userPublicKey) {
|
||||
if( [42, 142].contains( event.eventData.kind) ) {
|
||||
String channelId = event.eventData.getChannelIdForKind4x();
|
||||
@ -44,7 +46,7 @@ Set<String> getUserChannels(Set<Event> userEvents, String userPublicKey) {
|
||||
userChannels.add(event.eventData.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return userChannels;
|
||||
}
|
||||
@ -88,11 +90,11 @@ Set<String> getpTags(Set<Event> events, int numMostFrequent) {
|
||||
|
||||
Set<String> getOnlyUserEvents(Set<Event> initialEvents, String userPubkey) {
|
||||
Set<String> userEvents = {};
|
||||
initialEvents.forEach((event) {
|
||||
for (var event in initialEvents) {
|
||||
if( event.eventData.pubkey == userPubkey) {
|
||||
userEvents.add(event.eventData.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
return userEvents;
|
||||
}
|
||||
|
||||
|
@ -22,14 +22,13 @@ String getPostKindFrom(enumRoomType eType) {
|
||||
}
|
||||
|
||||
Set<String>? getTagsFromContent(String content) {
|
||||
Set<String>? tags = null;
|
||||
Set<String>? tags;
|
||||
|
||||
String regexp1 = '(#[a-zA-Z0-9_\-]+ )|(#[a-zA-Z0-9_\-]+)\$';
|
||||
String regexp1 = '(#[a-zA-Z0-9_-]+ )|(#[a-zA-Z0-9_-]+)\$';
|
||||
RegExp httpRegExp = RegExp(regexp1);
|
||||
|
||||
for( var match in httpRegExp.allMatches(content) ) {
|
||||
if( tags == null)
|
||||
tags = {};
|
||||
tags ??= {};
|
||||
|
||||
tags.add( content.substring(match.start + 1, match.end).trim() );
|
||||
}
|
||||
@ -84,31 +83,35 @@ extension StringX on String {
|
||||
|
||||
int isChannelPageNumber(int max) {
|
||||
|
||||
if(this.length < 2 || this[0] != '/') {
|
||||
if(length < 2 || this[0] != '/') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
String rest = this.substring(1);
|
||||
String rest = substring(1);
|
||||
|
||||
//print("rest = $rest");
|
||||
int? n = int.tryParse(rest);
|
||||
if( n != null) {
|
||||
if( n < max)
|
||||
if( n < max) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
isEnglish( ) {
|
||||
// since smaller words can be smileys they should not be translated
|
||||
if( length < 10)
|
||||
if( length < 10) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if( !isLatinAlphabet())
|
||||
if( !isLatinAlphabet()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isRomanceLanguage())
|
||||
if (isRomanceLanguage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -127,7 +130,7 @@ extension StringX on String {
|
||||
|
||||
Set<String> romanceWords = frenchWords.union(spanishWords).union(portugeseWords);
|
||||
for( String word in romanceWords) {
|
||||
if( this.toLowerCase().contains(" $word ")) {
|
||||
if( toLowerCase().contains(" $word ")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -208,7 +211,7 @@ String unEscapeChars(String str) {
|
||||
return temp;
|
||||
}
|
||||
|
||||
void printUnderlined(String x) => { stdout.write("$x\n${getNumDashes(x.length)}\n")};
|
||||
void printUnderlined(String x) { stdout.write("$x\n${getNumDashes(x.length)}\n");}
|
||||
|
||||
String getNumSpaces(int num) {
|
||||
String s = "";
|
||||
@ -228,7 +231,7 @@ String getNumDashes(int num, [String dashType = "-"]) {
|
||||
|
||||
List<List<int>> getUrlRanges(String s) {
|
||||
List<List<int>> urlRanges = [];
|
||||
String regexp1 = "http[s]*:\/\/[a-zA-Z0-9]+([.a-zA-Z0-9/_\\-\\#\\+=\\&\\?]*)";
|
||||
String regexp1 = "http[s]*://[a-zA-Z0-9]+([.a-zA-Z0-9/_\\-\\#\\+=\\&\\?]*)";
|
||||
|
||||
RegExp httpRegExp = RegExp(regexp1);
|
||||
for( var match in httpRegExp.allMatches(s) ) {
|
||||
@ -273,11 +276,13 @@ List<int>? getTypeAndModule(String str) {
|
||||
|
||||
bool sanityChecked(String lnInvoice) {
|
||||
|
||||
if( lnInvoice.length < gMinLnInvoiceLength)
|
||||
if( lnInvoice.length < gMinLnInvoiceLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if( lnInvoice.substring(0, 4).toLowerCase() != "lnbc")
|
||||
if( lnInvoice.substring(0, 4).toLowerCase() != "lnbc") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -306,7 +311,7 @@ String expandLNInvoices(String content) {
|
||||
}
|
||||
|
||||
qrStr = getPubkeyAsQrString(lnInvoice, typeAndModule[0], typeAndModule[1], "");
|
||||
content = content.substring(0, match.start) + ":-\n\n" + qrStr + "\n\n" + content.substring(match.end);
|
||||
content = "${content.substring(0, match.start)}:-\n\n$qrStr\n\n${content.substring(match.end)}";
|
||||
}
|
||||
|
||||
return content;
|
||||
@ -319,7 +324,7 @@ String getPubkeyAsQrString(String str, [int typeNumber = 4, moduleCount = 33, St
|
||||
String output = "";
|
||||
|
||||
final qrCode = QrCode(typeNumber, QrErrorCorrectLevel.L)
|
||||
..addData('$str');
|
||||
..addData(str);
|
||||
final qrImage = QrImage(qrCode);
|
||||
|
||||
assert( qrImage.moduleCount == moduleCount);
|
||||
@ -372,8 +377,9 @@ String getStringFromUser(String prompt, [String defaultValue=""] ) {
|
||||
stdout.write(prompt);
|
||||
str = (stdin.readLineSync())??"";
|
||||
|
||||
if( str.length == 0)
|
||||
if( str.isEmpty) {
|
||||
str = defaultValue;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -399,21 +405,21 @@ String getCommaSeparatedInts(Set<int>? kind) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if( kind.length == 0) {
|
||||
if( kind.isEmpty) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String strKind = "";
|
||||
int i = 0;
|
||||
|
||||
kind.forEach((k) {
|
||||
for (var k in kind) {
|
||||
String comma = ",";
|
||||
if( i == kind.length-1) {
|
||||
comma = "";
|
||||
}
|
||||
strKind = strKind + k.toString() + comma;
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
return strKind;
|
||||
}
|
||||
@ -432,16 +438,14 @@ String getKindRequest(String subscriptionId, List<int> kind, int limit, int sinc
|
||||
return strRequest;
|
||||
}
|
||||
|
||||
String getUserRequest(String subscriptionId, String publicKey, int numUserEvents, int sinceWhen, [Set<int>? _kind = null]) {
|
||||
String getUserRequest(String subscriptionId, String publicKey, int numUserEvents, int sinceWhen, [Set<int>? kind]) {
|
||||
Set<int> kind = {};
|
||||
if( _kind != null) {
|
||||
kind = _kind;
|
||||
}
|
||||
kind = kind;
|
||||
|
||||
String strKind = getCommaSeparatedInts(kind);
|
||||
|
||||
String strKindSection = "";
|
||||
if( strKind.length > 0) {
|
||||
if( strKind.isNotEmpty) {
|
||||
strKindSection = '"kinds":[$strKind],';
|
||||
}
|
||||
|
||||
@ -477,12 +481,12 @@ String getIdAndMentionRequest(String subscriptionId, Set<String> ids, int numUse
|
||||
|
||||
var strSubscription1 = '["REQ","$subscriptionId",{ "$tagToGet": [';
|
||||
var strSubscription2 ='], "limit": $numUserEvents $idStrTime } ]';
|
||||
String req = '["REQ","$subscriptionId",{ "$tagToGet": [' + getCommaSeparatedQuotedStrs(ids) + '], "limit": $numUserEvents $mentionStrTime},{"$idString":[' + getCommaSeparatedQuotedStrs(ids) + ']$idStrTime}]';
|
||||
String req = '["REQ","$subscriptionId",{ "$tagToGet": [${getCommaSeparatedQuotedStrs(ids)}], "limit": $numUserEvents $mentionStrTime},{"$idString":[${getCommaSeparatedQuotedStrs(ids)}]$idStrTime}]';
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
String getMultiUserRequest(String subscriptionId, Set<String> publicKeys, int numUserEvents, int sinceWhen, [Set<int>? kind = null]) {
|
||||
String getMultiUserRequest(String subscriptionId, Set<String> publicKeys, int numUserEvents, int sinceWhen, [Set<int>? kind]) {
|
||||
String strTime = "";
|
||||
if( sinceWhen != 0) {
|
||||
strTime = ', "since": ${sinceWhen.toString()}';
|
||||
@ -491,7 +495,7 @@ String getMultiUserRequest(String subscriptionId, Set<String> publicKeys, int nu
|
||||
String strKind = getCommaSeparatedInts(kind);
|
||||
|
||||
String strKindSection = "";
|
||||
if( strKind.length > 0) {
|
||||
if( strKind.isNotEmpty) {
|
||||
strKindSection = '"kinds":[$strKind],';
|
||||
}
|
||||
|
||||
@ -508,14 +512,14 @@ void printSet( Set<String> toPrint, [ String prefix = "", String separator = ""]
|
||||
stdout.write(prefix);
|
||||
|
||||
int i = 0;
|
||||
toPrint.forEach((element) {
|
||||
for (var element in toPrint) {
|
||||
if( i != 0) {
|
||||
stdout.write(separator);
|
||||
}
|
||||
|
||||
stdout.write(element);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
stdout.write("\n");
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,8 @@ homepage: https://github.com/vishalxl/nostr_console
|
||||
|
||||
|
||||
environment:
|
||||
sdk: '>=2.17.3 <3.0.0'
|
||||
sdk: '>=2.17.3 <4.0.0'
|
||||
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
@ -107,3 +108,5 @@ dependencies:
|
||||
logging: ^1.0.2
|
||||
kepler: ^1.0.3
|
||||
qr: ^3.0.1
|
||||
pointycastle: any
|
||||
http: any
|
||||
|
@ -221,11 +221,11 @@ String expectedResult =
|
||||
"11 https://github.com/nostr-protocol/nips/blob/master/16.md#ephemeral-events",
|
||||
"https://res.cloudinary.com/eskema/image/upload/v1669030722/306072883_413474904244526_502927779121754777_n.jpg_l6je2d.jpg"];
|
||||
|
||||
urls.forEach((url) {
|
||||
for (var url in urls) {
|
||||
String res = makeParagraphAtDepth(url, 30);
|
||||
//print(url); print(res);print("");
|
||||
expect( res, url);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -233,27 +233,33 @@ String expectedResult =
|
||||
Set<Event> initialEvents = {}; // collect all events here and then create tree out of them
|
||||
|
||||
|
||||
String input_filename = 'test_event_file.csv';
|
||||
initialEvents = await readEventsFromFile(input_filename);
|
||||
String inputFilename = 'test_event_file.csv';
|
||||
initialEvents = readEventsFromFile(inputFilename);
|
||||
|
||||
int numFilePosts = 0;
|
||||
// count events
|
||||
initialEvents.forEach((element) { element.eventData.kind == 1? numFilePosts++: numFilePosts;});
|
||||
for (var element in initialEvents) { element.eventData.kind == 1? numFilePosts++: numFilePosts;}
|
||||
//print("read $numFilePosts posts from file $gEventsFilename");
|
||||
expect(numFilePosts, 3486, reason:'Verify right number of kind 1 posts');
|
||||
|
||||
Store node = await getTree(initialEvents);
|
||||
Store node = getTree(initialEvents);
|
||||
|
||||
expect(0, node.getNumDirectRooms(), reason:'verify correct number of direct chat rooms created');
|
||||
|
||||
int numKind4xChannels = 0;
|
||||
node.channels.forEach((channel) => channel.roomType == enumRoomType.kind40? numKind4xChannels++:1);
|
||||
for (var channel in node.channels) {
|
||||
channel.roomType == enumRoomType.kind40? numKind4xChannels++:1;
|
||||
}
|
||||
|
||||
int numTTagChannels = 0;
|
||||
node.channels.forEach((channel) => channel.roomType == enumRoomType.RoomTTag? numTTagChannels++:1);
|
||||
for (var channel in node.channels) {
|
||||
channel.roomType == enumRoomType.RoomTTag? numTTagChannels++:1;
|
||||
}
|
||||
|
||||
int numLocationTagChannels = 0;
|
||||
node.channels.forEach((channel) => channel.roomType == enumRoomType.RoomLocationTag? numLocationTagChannels++:1);
|
||||
for (var channel in node.channels) {
|
||||
channel.roomType == enumRoomType.RoomLocationTag? numLocationTagChannels++:1;
|
||||
}
|
||||
|
||||
expect(78, numKind4xChannels, reason: 'verify correct number of public channels created of kind 4x');
|
||||
expect(41, numTTagChannels, reason: 'verify correct number of public channels created of T tag type');
|
||||
|
Loading…
x
Reference in New Issue
Block a user