Setting up relations
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "98aa54dd7fe776faca364638070a3871",
|
||||
"identityHash": "296c3251f1f835c144c94c7ff1598939",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "BroadcastNostrEventReceipt",
|
||||
@@ -263,62 +263,35 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "InReplyToPost",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `inReplyToPostId` TEXT NOT NULL, `inReplyToPostTags` TEXT NOT NULL, `inReplyToPostCreatedAt` INTEGER NOT NULL, `inReplyToPostContent` TEXT NOT NULL, `inReplyToPostAuthorPublicKey` TEXT NOT NULL, `content` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `profilePublicKey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`inReplyToPostAuthorPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`inReplyToPostId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"tableName": "InReplyToRelation",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`replyingNostrEventId` TEXT NOT NULL, `inReplyToNostrEventId` TEXT NOT NULL, `inReplyToProfilePublicKey` TEXT, `inReplyToRootNostrEventId` TEXT, `inReplyToRootProfilePublicKey` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, PRIMARY KEY(`replyingNostrEventId`, `inReplyToNostrEventId`), FOREIGN KEY(`inReplyToProfilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`inReplyToRootProfilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`replyingNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`inReplyToNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`inReplyToRootNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"fieldPath": "replyingNostrEventId",
|
||||
"columnName": "replyingNostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToPostId",
|
||||
"columnName": "inReplyToPostId",
|
||||
"fieldPath": "inReplyToNostrEventId",
|
||||
"columnName": "inReplyToNostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToPostTags",
|
||||
"columnName": "inReplyToPostTags",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
"fieldPath": "inReplyToProfilePublicKey",
|
||||
"columnName": "inReplyToProfilePublicKey",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToPostCreatedAt",
|
||||
"columnName": "inReplyToPostCreatedAt",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
"fieldPath": "inReplyToRootNostrEventId",
|
||||
"columnName": "inReplyToRootNostrEventId",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToPostContent",
|
||||
"columnName": "inReplyToPostContent",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToPostAuthorPublicKey",
|
||||
"columnName": "inReplyToPostAuthorPublicKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "nostrEventId",
|
||||
"columnName": "nostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "profilePublicKey",
|
||||
"columnName": "profilePublicKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
"fieldPath": "inReplyToRootProfilePublicKey",
|
||||
"columnName": "inReplyToRootProfilePublicKey",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "createdAt",
|
||||
@@ -347,55 +320,22 @@
|
||||
"fieldPath": "deletedAt",
|
||||
"columnName": "deletedAt",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "broadcastedAt",
|
||||
"columnName": "broadcastedAt",
|
||||
"affinity": "INTEGER"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
"replyingNostrEventId",
|
||||
"inReplyToNostrEventId"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_InReplyToPost_profilePublicKey",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"profilePublicKey"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_InReplyToPost_profilePublicKey` ON `${TABLE_NAME}` (`profilePublicKey`)"
|
||||
},
|
||||
{
|
||||
"name": "index_InReplyToPost_nostrEventId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"nostrEventId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_InReplyToPost_nostrEventId` ON `${TABLE_NAME}` (`nostrEventId`)"
|
||||
},
|
||||
{
|
||||
"name": "index_InReplyToPost_inReplyToPostId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"inReplyToPostId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_InReplyToPost_inReplyToPostId` ON `${TABLE_NAME}` (`inReplyToPostId`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "Profile",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"profilePublicKey"
|
||||
"inReplyToProfilePublicKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"publicKey"
|
||||
@@ -406,7 +346,7 @@
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"inReplyToPostAuthorPublicKey"
|
||||
"inReplyToRootProfilePublicKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"publicKey"
|
||||
@@ -417,18 +357,29 @@
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"nostrEventId"
|
||||
"replyingNostrEventId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "Post",
|
||||
"table": "NostrEvent",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"inReplyToPostId"
|
||||
"inReplyToNostrEventId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "NostrEvent",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"inReplyToRootNostrEventId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
@@ -438,11 +389,11 @@
|
||||
},
|
||||
{
|
||||
"tableName": "Mention",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`publicKey` TEXT NOT NULL, `relayUrl` TEXT, `nostrEventId` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`nostrEventId`, `publicKey`), FOREIGN KEY(`publicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`mentionedPublicKey` TEXT NOT NULL, `relayUrl` TEXT, `nostrEventId` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`nostrEventId`, `mentionedPublicKey`), FOREIGN KEY(`mentionedPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "publicKey",
|
||||
"columnName": "publicKey",
|
||||
"fieldPath": "mentionedPublicKey",
|
||||
"columnName": "mentionedPublicKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
@@ -490,7 +441,7 @@
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"nostrEventId",
|
||||
"publicKey"
|
||||
"mentionedPublicKey"
|
||||
]
|
||||
},
|
||||
"foreignKeys": [
|
||||
@@ -499,7 +450,7 @@
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"publicKey"
|
||||
"mentionedPublicKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"publicKey"
|
||||
@@ -520,7 +471,7 @@
|
||||
},
|
||||
{
|
||||
"tableName": "NostrEvent",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `content` TEXT NOT NULL, `sig` TEXT NOT NULL, `quotedNostrEventId` TEXT, `rootNostrEventId` TEXT, `replyNostrEventId` TEXT, `taggedNostrEventId` TEXT, `taggedNostrEventRelayUrl` TEXT, `unsignedNostrEventId` INTEGER, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`))",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `content` TEXT NOT NULL, `sig` TEXT NOT NULL, `quotedNostrEventId` TEXT, `quotedAuthorPublicKey` TEXT, `inReplyToNostrEventId` TEXT, `inReplyToAuthorPublicKey` TEXT, `inReplyToRootNostrEventId` TEXT, `inReplyToRootAuthorPublicKey` TEXT, `repostedNostrEventId` TEXT, `repostedAuthorPublicKey` TEXT, `unsignedNostrEventId` INTEGER, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
@@ -564,23 +515,38 @@
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "rootNostrEventId",
|
||||
"columnName": "rootNostrEventId",
|
||||
"fieldPath": "quotedAuthorPublicKey",
|
||||
"columnName": "quotedAuthorPublicKey",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "replyNostrEventId",
|
||||
"columnName": "replyNostrEventId",
|
||||
"fieldPath": "inReplyToNostrEventId",
|
||||
"columnName": "inReplyToNostrEventId",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "taggedNostrEventId",
|
||||
"columnName": "taggedNostrEventId",
|
||||
"fieldPath": "inReplyToAuthorPublicKey",
|
||||
"columnName": "inReplyToAuthorPublicKey",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "taggedNostrEventRelayUrl",
|
||||
"columnName": "taggedNostrEventRelayUrl",
|
||||
"fieldPath": "inReplyToRootNostrEventId",
|
||||
"columnName": "inReplyToRootNostrEventId",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToRootAuthorPublicKey",
|
||||
"columnName": "inReplyToRootAuthorPublicKey",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "repostedNostrEventId",
|
||||
"columnName": "repostedNostrEventId",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "repostedAuthorPublicKey",
|
||||
"columnName": "repostedAuthorPublicKey",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
@@ -652,22 +618,22 @@
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_NostrEvent_quotedNostrEventId` ON `${TABLE_NAME}` (`quotedNostrEventId`)"
|
||||
},
|
||||
{
|
||||
"name": "index_NostrEvent_rootNostrEventId",
|
||||
"name": "index_NostrEvent_inReplyToNostrEventId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"rootNostrEventId"
|
||||
"inReplyToNostrEventId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_NostrEvent_rootNostrEventId` ON `${TABLE_NAME}` (`rootNostrEventId`)"
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_NostrEvent_inReplyToNostrEventId` ON `${TABLE_NAME}` (`inReplyToNostrEventId`)"
|
||||
},
|
||||
{
|
||||
"name": "index_NostrEvent_replyNostrEventId",
|
||||
"name": "index_NostrEvent_inReplyToRootNostrEventId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"replyNostrEventId"
|
||||
"inReplyToRootNostrEventId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_NostrEvent_replyNostrEventId` ON `${TABLE_NAME}` (`replyNostrEventId`)"
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_NostrEvent_inReplyToRootNostrEventId` ON `${TABLE_NAME}` (`inReplyToRootNostrEventId`)"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -986,62 +952,25 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "QuotedPost",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `quotedPostId` TEXT NOT NULL, `quotedPostTags` TEXT NOT NULL, `quotedPostCreatedAt` INTEGER NOT NULL, `quotedPostContent` TEXT NOT NULL, `quotedPostAuthorPublicKey` TEXT NOT NULL, `content` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `profilePublicKey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`quotedPostAuthorPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`quotedPostId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"tableName": "QuotedRelation",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`quotingNostrEventId` TEXT NOT NULL, `quotedNostrEventId` TEXT NOT NULL, `quotedProfilePublicKey` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`quotingNostrEventId`, `quotedNostrEventId`), FOREIGN KEY(`quotedProfilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`quotingNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`quotedNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"fieldPath": "quotingNostrEventId",
|
||||
"columnName": "quotingNostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "quotedPostId",
|
||||
"columnName": "quotedPostId",
|
||||
"fieldPath": "quotedNostrEventId",
|
||||
"columnName": "quotedNostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "quotedPostTags",
|
||||
"columnName": "quotedPostTags",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "quotedPostCreatedAt",
|
||||
"columnName": "quotedPostCreatedAt",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "quotedPostContent",
|
||||
"columnName": "quotedPostContent",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "quotedPostAuthorPublicKey",
|
||||
"columnName": "quotedPostAuthorPublicKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "nostrEventId",
|
||||
"columnName": "nostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "profilePublicKey",
|
||||
"columnName": "profilePublicKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
"fieldPath": "quotedProfilePublicKey",
|
||||
"columnName": "quotedProfilePublicKey",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "createdAt",
|
||||
@@ -1080,56 +1009,17 @@
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
"quotingNostrEventId",
|
||||
"quotedNostrEventId"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_QuotedPost_profilePublicKey",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"profilePublicKey"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_QuotedPost_profilePublicKey` ON `${TABLE_NAME}` (`profilePublicKey`)"
|
||||
},
|
||||
{
|
||||
"name": "index_QuotedPost_nostrEventId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"nostrEventId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_QuotedPost_nostrEventId` ON `${TABLE_NAME}` (`nostrEventId`)"
|
||||
},
|
||||
{
|
||||
"name": "index_QuotedPost_quotedPostId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"quotedPostId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_QuotedPost_quotedPostId` ON `${TABLE_NAME}` (`quotedPostId`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "Profile",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"profilePublicKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"publicKey"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "Profile",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"quotedPostAuthorPublicKey"
|
||||
"quotedProfilePublicKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"publicKey"
|
||||
@@ -1140,18 +1030,18 @@
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"nostrEventId"
|
||||
"quotingNostrEventId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "Post",
|
||||
"table": "NostrEvent",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"quotedPostId"
|
||||
"quotedNostrEventId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
@@ -1378,62 +1268,25 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "Repost",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `repostedPostId` TEXT NOT NULL, `repostedPostTags` TEXT NOT NULL, `repostedPostCreatedAt` INTEGER NOT NULL, `repostedPostContent` TEXT NOT NULL, `repostedPostAuthorPublicKey` TEXT NOT NULL, `content` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `profilePublicKey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`repostedPostAuthorPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`repostedPostId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"tableName": "RepostedRelation",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`repostingNostrEventId` TEXT NOT NULL, `repostedNostrEventId` TEXT NOT NULL, `repostedProfilePublicKey` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`repostingNostrEventId`, `repostedNostrEventId`), FOREIGN KEY(`repostedProfilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`repostedNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`repostingNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"fieldPath": "repostingNostrEventId",
|
||||
"columnName": "repostingNostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "repostedPostId",
|
||||
"columnName": "repostedPostId",
|
||||
"fieldPath": "repostedNostrEventId",
|
||||
"columnName": "repostedNostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "repostedPostTags",
|
||||
"columnName": "repostedPostTags",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "repostedPostCreatedAt",
|
||||
"columnName": "repostedPostCreatedAt",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "repostedPostContent",
|
||||
"columnName": "repostedPostContent",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "repostedPostAuthorPublicKey",
|
||||
"columnName": "repostedPostAuthorPublicKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "nostrEventId",
|
||||
"columnName": "nostrEventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "profilePublicKey",
|
||||
"columnName": "profilePublicKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
"fieldPath": "repostedProfilePublicKey",
|
||||
"columnName": "repostedProfilePublicKey",
|
||||
"affinity": "TEXT"
|
||||
},
|
||||
{
|
||||
"fieldPath": "createdAt",
|
||||
@@ -1472,56 +1325,17 @@
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
"repostingNostrEventId",
|
||||
"repostedNostrEventId"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_Repost_profilePublicKey",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"profilePublicKey"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Repost_profilePublicKey` ON `${TABLE_NAME}` (`profilePublicKey`)"
|
||||
},
|
||||
{
|
||||
"name": "index_Repost_nostrEventId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"nostrEventId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Repost_nostrEventId` ON `${TABLE_NAME}` (`nostrEventId`)"
|
||||
},
|
||||
{
|
||||
"name": "index_Repost_repostedPostId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"repostedPostId"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Repost_repostedPostId` ON `${TABLE_NAME}` (`repostedPostId`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "Profile",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"profilePublicKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"publicKey"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "Profile",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"repostedPostAuthorPublicKey"
|
||||
"repostedProfilePublicKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"publicKey"
|
||||
@@ -1532,18 +1346,18 @@
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"nostrEventId"
|
||||
"repostedNostrEventId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "Post",
|
||||
"table": "NostrEvent",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"repostedPostId"
|
||||
"repostingNostrEventId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
@@ -2004,7 +1818,7 @@
|
||||
],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '98aa54dd7fe776faca364638070a3871')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '296c3251f1f835c144c94c7ff1598939')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -4,17 +4,17 @@ import ac.cord.auxiliary.compose.database.converters.AuxConverters
|
||||
import ac.cord.auxiliary.compose.database.dao.BroadcastNostrEventReceiptDao
|
||||
import ac.cord.auxiliary.compose.database.dao.BroadcastNostrEventRequestDao
|
||||
import ac.cord.auxiliary.compose.database.dao.ConnectionDao
|
||||
import ac.cord.auxiliary.compose.database.dao.InReplyToPostDao
|
||||
import ac.cord.auxiliary.compose.database.dao.InReplyToRelationDao
|
||||
import ac.cord.auxiliary.compose.database.dao.MentionDao
|
||||
import ac.cord.auxiliary.compose.database.dao.NostrDao
|
||||
import ac.cord.auxiliary.compose.database.dao.NostrEventDao
|
||||
import ac.cord.auxiliary.compose.database.dao.PostDao
|
||||
import ac.cord.auxiliary.compose.database.dao.ProfileDao
|
||||
import ac.cord.auxiliary.compose.database.dao.QuotedPostDao
|
||||
import ac.cord.auxiliary.compose.database.dao.QuotedRelationDao
|
||||
import ac.cord.auxiliary.compose.database.dao.ReactionDao
|
||||
import ac.cord.auxiliary.compose.database.dao.RecentSearchDao
|
||||
import ac.cord.auxiliary.compose.database.dao.RelayDao
|
||||
import ac.cord.auxiliary.compose.database.dao.RepostDao
|
||||
import ac.cord.auxiliary.compose.database.dao.RepostedRelationDao
|
||||
import ac.cord.auxiliary.compose.database.dao.SynchronizeNostrEventRequestDao
|
||||
import ac.cord.auxiliary.compose.database.dao.SynchronizeNostrEventResultDao
|
||||
import ac.cord.auxiliary.compose.database.dao.UnsignedNostrEventDao
|
||||
@@ -22,16 +22,16 @@ import ac.cord.auxiliary.compose.database.dao.ZapDao
|
||||
import ac.cord.auxiliary.compose.database.model.BroadcastNostrEventReceipt
|
||||
import ac.cord.auxiliary.compose.database.model.BroadcastNostrEventRequest
|
||||
import ac.cord.auxiliary.compose.database.model.Connection
|
||||
import ac.cord.auxiliary.compose.database.model.InReplyToPost
|
||||
import ac.cord.auxiliary.compose.database.model.InReplyToRelation
|
||||
import ac.cord.auxiliary.compose.database.model.Mention
|
||||
import ac.cord.auxiliary.compose.database.model.NostrEvent
|
||||
import ac.cord.auxiliary.compose.database.model.Post
|
||||
import ac.cord.auxiliary.compose.database.model.Profile
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedPost
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedRelation
|
||||
import ac.cord.auxiliary.compose.database.model.Reaction
|
||||
import ac.cord.auxiliary.compose.database.model.RecentSearch
|
||||
import ac.cord.auxiliary.compose.database.model.Relay
|
||||
import ac.cord.auxiliary.compose.database.model.Repost
|
||||
import ac.cord.auxiliary.compose.database.model.RepostedRelation
|
||||
import ac.cord.auxiliary.compose.database.model.SynchronizeNostrEventRequest
|
||||
import ac.cord.auxiliary.compose.database.model.SynchronizeNostrEventResult
|
||||
import ac.cord.auxiliary.compose.database.model.UnsignedNostrEvent
|
||||
@@ -50,16 +50,16 @@ val GENESIS_AT = Instant.fromEpochMilliseconds(1231006505000L)
|
||||
BroadcastNostrEventReceipt::class,
|
||||
BroadcastNostrEventRequest::class,
|
||||
Connection::class,
|
||||
InReplyToPost::class,
|
||||
InReplyToRelation::class,
|
||||
Mention::class,
|
||||
NostrEvent::class,
|
||||
Post::class,
|
||||
Profile::class,
|
||||
QuotedPost::class,
|
||||
QuotedRelation::class,
|
||||
Reaction::class,
|
||||
RecentSearch::class,
|
||||
Relay::class,
|
||||
Repost::class,
|
||||
RepostedRelation::class,
|
||||
SynchronizeNostrEventRequest::class,
|
||||
SynchronizeNostrEventResult::class,
|
||||
UnsignedNostrEvent::class,
|
||||
@@ -73,7 +73,7 @@ abstract class AuxDatabase: RoomDatabase() {
|
||||
abstract fun broadcastNostrEventRequestDao(): BroadcastNostrEventRequestDao
|
||||
abstract fun connectionDao(): ConnectionDao
|
||||
|
||||
abstract fun inReplyToPostDao(): InReplyToPostDao
|
||||
abstract fun inReplyToRelationDao(): InReplyToRelationDao
|
||||
|
||||
abstract fun mentionDao(): MentionDao
|
||||
|
||||
@@ -83,7 +83,7 @@ abstract class AuxDatabase: RoomDatabase() {
|
||||
abstract fun postDao(): PostDao
|
||||
abstract fun profileDao(): ProfileDao
|
||||
|
||||
abstract fun quotedPostDao(): QuotedPostDao
|
||||
abstract fun quotedRelationDao(): QuotedRelationDao
|
||||
|
||||
abstract fun reactionDao(): ReactionDao
|
||||
|
||||
@@ -91,7 +91,7 @@ abstract class AuxDatabase: RoomDatabase() {
|
||||
|
||||
abstract fun relayDao(): RelayDao
|
||||
|
||||
abstract fun repostDao(): RepostDao
|
||||
abstract fun repostedRelationDao(): RepostedRelationDao
|
||||
|
||||
abstract fun synchronizeNostrEventRequestDao(): SynchronizeNostrEventRequestDao
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.InReplyToPost
|
||||
import ac.cord.auxiliary.compose.database.model.Post
|
||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalPost
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
|
||||
@Dao
|
||||
interface InReplyToPostDao {
|
||||
@Insert
|
||||
suspend fun insert(inReplyToPost: InReplyToPost)
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(inReplyToPost: InReplyToPost)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.InReplyToRelation
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
|
||||
@Dao
|
||||
interface InReplyToRelationDao {
|
||||
@Query("SELECT * FROM InReplyToRelation WHERE replyingNostrEventId = :replyingNostrEventId")
|
||||
fun getRepostByReplyingNostrEventId(replyingNostrEventId: String): InReplyToRelation?
|
||||
|
||||
@Query("SELECT * FROM InReplyToRelation WHERE inReplyToNostrEventId = :inReplyToNostrEventId")
|
||||
fun getRepostByInReplyToNostrEventId(inReplyToNostrEventId: String): InReplyToRelation?
|
||||
|
||||
@Insert
|
||||
suspend fun insert(inReplyToRelation: InReplyToRelation)
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(inReplyToRelation: InReplyToRelation)
|
||||
}
|
||||
@@ -18,12 +18,9 @@ import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers
|
||||
import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent
|
||||
import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.list.ChannelListEvent
|
||||
import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.relayLists.IndexerRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.relayLists.RelayFeedsListEvent
|
||||
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.QAddressableTag
|
||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.QEventTag
|
||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.firstTaggedQuote
|
||||
import kotlin.time.Clock
|
||||
|
||||
@Dao
|
||||
@@ -187,41 +184,141 @@ abstract class NostrDao(
|
||||
}
|
||||
|
||||
// Sync tagged events and authors...
|
||||
// nostrEvent.tags.firstTaggedQuote()?.let { taggedQuote ->
|
||||
// when (taggedQuote) {
|
||||
// is QEventTag -> {
|
||||
// Triple(
|
||||
// taggedQuote.eventId,
|
||||
// taggedQuote.author,
|
||||
// taggedQuote.relay,
|
||||
// )
|
||||
// }
|
||||
// is QAddressableTag -> {
|
||||
// Triple(
|
||||
// taggedQuote.address.dTag,
|
||||
// taggedQuote.address.pubKeyHex,
|
||||
// taggedQuote.relay,
|
||||
// )
|
||||
// }
|
||||
// else -> null
|
||||
// }?.let { quotedEventData ->
|
||||
// val quotedNostrEvent = database.nostrEventDao().getNostrEventById(quotedEventData.first)
|
||||
//
|
||||
// if (quotedNostrEvent == null) {
|
||||
//// val quotedPost = database.postDao().getPostById(quotedEventData.first)
|
||||
//
|
||||
//// if (quotedPost == null) {
|
||||
//// // Persist PlaceHolder and sync
|
||||
//// database.postDao().insert(
|
||||
//// Post(
|
||||
//// id = quotedEventData.first,
|
||||
//// createdAt = GENESIS_AT,
|
||||
//// nostrEventId = nostrEvent.id, // Will get overwriting by sync handled by tagged events...
|
||||
//// content = "sync required",
|
||||
//// profilePublicKey = nostrEvent.pubKey // Will get overwriting by sync handled by tagged events...
|
||||
//// )
|
||||
//// )
|
||||
//// }
|
||||
////
|
||||
//// quotedEventData.second?.let { authorPubkey ->
|
||||
//// val repostedPostProfile = database.profileDao().getProfileByPublicKey(authorPubkey)
|
||||
////
|
||||
//// if (repostedPostProfile == null) {
|
||||
//// // Persist PlaceHolder and sync
|
||||
//// database.profileDao().insertPlaceholderProfile(
|
||||
//// Profile(
|
||||
//// publicKey = authorPubkey,
|
||||
//// createdAt = GENESIS_AT,
|
||||
//// nostrEventId = nostrEvent.id, // Will get overwriting by sync handled by tagged events...
|
||||
//// )
|
||||
//// )
|
||||
//// profilePublicKeysToSync.add(
|
||||
//// authorPubkey
|
||||
//// )
|
||||
//// } else if (repostedPostProfile.createdAt == GENESIS_AT && level == 0) {
|
||||
//// logger.i("${level} This is a placeholder profile... that might need to get synced...: $repostedPostProfile")
|
||||
//// profilePublicKeysToSync.add(authorPubkey)
|
||||
//// }
|
||||
//// }
|
||||
////
|
||||
//// database.quotedPostDao()
|
||||
//
|
||||
// val recommendRelayUrl = quotedEventData.third?.url
|
||||
//
|
||||
// val synchronizeNostrEventRequests = if (recommendRelayUrl != null) {
|
||||
// eventIdsToSync.add(quotedEventData.first)
|
||||
//
|
||||
// listOf(
|
||||
// SynchronizeNostrEventRequest(
|
||||
// purpose = "synchronization",
|
||||
// synchronizationFilters = arrayOf(
|
||||
// SynchronizationFilter(
|
||||
// ids = arrayOf(quotedEventData.first)
|
||||
// )
|
||||
// ),
|
||||
// relayURL = recommendRelayUrl,
|
||||
// isRecommendedRelay = true,
|
||||
// level = level + 1
|
||||
// )
|
||||
// )
|
||||
// } else {
|
||||
// eventIdsToSync.add(quotedEventData.first)
|
||||
// synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
// SynchronizeNostrEventRequest(
|
||||
// purpose = "synchronization",
|
||||
// synchronizationFilters = arrayOf(
|
||||
// SynchronizationFilter(
|
||||
// ids = arrayOf(quotedEventData.first)
|
||||
// )
|
||||
// ),
|
||||
// relayURL = synchronizationRelayURL,
|
||||
// level = level + 1
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// database.synchronizeNostrEventRequestDao().insert(
|
||||
// synchronizeNostrEventRequests
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
nostrEvent.tags.taggedEvents().take(4).forEach { taggedEvent -> // We only look at the first 3 tagged events...
|
||||
val taggedNostrEvent = database.nostrEventDao().getNostrEventById(taggedEvent.eventId)
|
||||
if (taggedNostrEvent == null) {
|
||||
val recommendRelayUrl = taggedEvent.relay?.url
|
||||
|
||||
val synchronizeNostrEventRequests = if (recommendRelayUrl != null) {
|
||||
eventIdsToSync.add(taggedEvent.eventId)
|
||||
listOf(
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
ids = arrayOf(taggedEvent.eventId)
|
||||
)
|
||||
),
|
||||
relayURL = recommendRelayUrl,
|
||||
isRecommendedRelay = true,
|
||||
level = level + 1
|
||||
)
|
||||
eventIdsToSync.add(taggedEvent.eventId)
|
||||
listOf(
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
ids = arrayOf(taggedEvent.eventId)
|
||||
)
|
||||
),
|
||||
relayURL = recommendRelayUrl,
|
||||
isRecommendedRelay = true,
|
||||
level = level + 1
|
||||
)
|
||||
)
|
||||
} else {
|
||||
eventIdsToSync.add(taggedEvent.eventId)
|
||||
synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
ids = arrayOf(taggedEvent.eventId)
|
||||
)
|
||||
),
|
||||
relayURL = synchronizationRelayURL,
|
||||
level = level + 1
|
||||
)
|
||||
} else {
|
||||
eventIdsToSync.add(taggedEvent.eventId)
|
||||
synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
SynchronizeNostrEventRequest(
|
||||
purpose = "synchronization",
|
||||
synchronizationFilters = arrayOf(
|
||||
SynchronizationFilter(
|
||||
ids = arrayOf(taggedEvent.eventId)
|
||||
)
|
||||
),
|
||||
relayURL = synchronizationRelayURL,
|
||||
level = level + 1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.synchronizeNostrEventRequestDao().insert(
|
||||
synchronizeNostrEventRequests
|
||||
@@ -232,6 +329,19 @@ abstract class NostrDao(
|
||||
nostrEvent.tags.taggedUsers().take(5).forEach { taggedUser -> // 5 tagged users...
|
||||
val recommendedRelay = taggedUser.relayHint?.url
|
||||
|
||||
val taggedProfile = database.profileDao().getProfileByPublicKey(taggedUser.pubKey)
|
||||
|
||||
if (taggedProfile == null) {
|
||||
// Save a placeholder
|
||||
database.profileDao().insertPlaceholderProfile(
|
||||
Profile(
|
||||
publicKey = taggedUser.pubKey,
|
||||
createdAt = GENESIS_AT,
|
||||
nostrEventId = nostrEvent.id, // Will get overwriting by sync,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val synchronizeNostrEventRequests = if (recommendedRelay != null) {
|
||||
// listOf(
|
||||
// SynchronizeNostrEventRequest(
|
||||
@@ -327,60 +437,144 @@ abstract class NostrDao(
|
||||
database.reactionDao().upsert(reaction)
|
||||
}
|
||||
|
||||
nostrEvent.toRepost()?.let { repost ->
|
||||
// Find or create placeHolder note that is being reposted
|
||||
val repostedPost = database.postDao().getPostById(repost.repostedPostId)
|
||||
nostrEvent.toQuotedRelation()?.let { quotedRelation ->
|
||||
val quotedNostrEvent = database.nostrEventDao().getNostrEventById(quotedRelation.quotedNostrEventId)
|
||||
|
||||
if (repostedPost == null) {
|
||||
// Persist PlaceHolder and sync
|
||||
database.postDao().insert(
|
||||
Post(
|
||||
id = repost.repostedPostId,
|
||||
val quotedProfilePublicKey = if (quotedNostrEvent == null) {
|
||||
eventIdsToSync.add(quotedRelation.quotedNostrEventId)
|
||||
|
||||
database.nostrEventDao().insert(
|
||||
NostrEvent(
|
||||
id = quotedRelation.quotedNostrEventId,
|
||||
content = "Pending Sync",
|
||||
createdAt = GENESIS_AT,
|
||||
nostrEventId = nostrEvent.id, // Will get overwriting by sync handled by tagged events...
|
||||
content = repost.repostedPostId,
|
||||
profilePublicKey = nostrEvent.pubKey // Will get overwriting by sync handled by tagged events...
|
||||
pubKey = nostrEvent.pubKey,
|
||||
sig = "",
|
||||
kind = nostrEvent.kind,
|
||||
tags = emptyArray()
|
||||
)
|
||||
)
|
||||
|
||||
quotedRelation.quotedProfilePublicKey
|
||||
} else {
|
||||
quotedNostrEvent.pubKey
|
||||
}
|
||||
|
||||
val repostedPostProfile = database.profileDao().getProfileByPublicKey(repost.repostedPostAuthorPublicKey)
|
||||
val quotedProfile = quotedProfilePublicKey?.let { database.profileDao().getProfileByPublicKey(it) }
|
||||
|
||||
if (repostedPostProfile == null) {
|
||||
// Persist PlaceHolder and sync
|
||||
if (quotedProfilePublicKey != null && quotedProfile == null) {
|
||||
database.profileDao().insertPlaceholderProfile(
|
||||
Profile(
|
||||
publicKey = repost.repostedPostAuthorPublicKey,
|
||||
publicKey = quotedProfilePublicKey,
|
||||
createdAt = GENESIS_AT,
|
||||
nostrEventId = nostrEvent.id, // Will get overwriting by sync handled by tagged events...
|
||||
nostrEventId = nostrEvent.id, // Will get overwriting by sync,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Might need to store placeholders
|
||||
database.quotedRelationDao().upsert(
|
||||
quotedRelation.copy(
|
||||
quotedProfilePublicKey = quotedProfilePublicKey
|
||||
)
|
||||
)
|
||||
}
|
||||
nostrEvent.toRepostedRelation()?.let { repostedRelation ->
|
||||
// Find or create placeHolder note that is being reposted
|
||||
val repostedNostrEvent = database.nostrEventDao().getNostrEventById(repostedRelation.repostedNostrEventId)
|
||||
|
||||
val repostedProfilePublicKey = if (repostedNostrEvent == null) {
|
||||
// Sync event...
|
||||
eventIdsToSync.add(repostedRelation.repostedNostrEventId)
|
||||
|
||||
database.nostrEventDao().insert(
|
||||
NostrEvent(
|
||||
id = repostedRelation.repostedNostrEventId,
|
||||
content = "Pending Sync",
|
||||
createdAt = GENESIS_AT,
|
||||
pubKey = nostrEvent.pubKey,
|
||||
sig = "",
|
||||
kind = nostrEvent.kind,
|
||||
tags = emptyArray()
|
||||
)
|
||||
)
|
||||
|
||||
// Request a sync for the post being replied to
|
||||
// database.synchronizeNostrEventRequestDao().insert(
|
||||
// synchronizationRelayURLs.map { synchronizationRelayURL ->
|
||||
// SynchronizeNostrEventRequest(
|
||||
// purpose = "synchronization",
|
||||
// synchronizationFilters = arrayOf(
|
||||
//
|
||||
// ),
|
||||
// relayURL = synchronizationRelayURL
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// synchronizationFilters.add(
|
||||
// SynchronizationFilter(
|
||||
// authors = arrayOf(repost.repostedPostAuthorPublicKey),
|
||||
// kinds = profileEventKinds
|
||||
// )
|
||||
// )
|
||||
profilePublicKeysToSync.add(
|
||||
repost.repostedPostAuthorPublicKey
|
||||
)
|
||||
} else if (repostedPostProfile.createdAt == GENESIS_AT && level == 0) {
|
||||
logger.i("${level} This is a placeholder profile... that might need to get synced...: $repostedPostProfile")
|
||||
profilePublicKeysToSync.add(repost.repostedPostAuthorPublicKey)
|
||||
repostedRelation.repostedProfilePublicKey
|
||||
} else {
|
||||
repostedNostrEvent.pubKey
|
||||
}
|
||||
|
||||
val repostedProfile = repostedProfilePublicKey?.let { database.profileDao().getProfileByPublicKey(it) }
|
||||
|
||||
if (repostedProfilePublicKey != null && repostedProfile == null) {
|
||||
database.profileDao().insertPlaceholderProfile(
|
||||
Profile(
|
||||
publicKey = repostedProfilePublicKey,
|
||||
createdAt = GENESIS_AT,
|
||||
nostrEventId = nostrEvent.id, // Will get overwriting by sync,
|
||||
)
|
||||
)
|
||||
}
|
||||
database.repostedRelationDao().upsert(
|
||||
repostedRelation.copy(
|
||||
repostedProfilePublicKey = repostedProfilePublicKey
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
nostrEvent.toInReplyToRelation()?.let { inReplyToRelation ->
|
||||
|
||||
val inReplyToNostrEvent = database.nostrEventDao().getNostrEventById(inReplyToRelation.inReplyToNostrEventId)
|
||||
|
||||
val inReplyToProfilePublicKey = if (inReplyToNostrEvent == null) {
|
||||
eventIdsToSync.add(inReplyToRelation.inReplyToNostrEventId)
|
||||
|
||||
database.nostrEventDao().insert(
|
||||
NostrEvent(
|
||||
id = inReplyToRelation.inReplyToNostrEventId,
|
||||
content = "Pending Sync",
|
||||
createdAt = GENESIS_AT,
|
||||
pubKey = nostrEvent.pubKey,
|
||||
sig = "",
|
||||
kind = nostrEvent.kind,
|
||||
tags = emptyArray()
|
||||
)
|
||||
)
|
||||
|
||||
inReplyToRelation.inReplyToProfilePublicKey
|
||||
} else {
|
||||
inReplyToNostrEvent.pubKey
|
||||
}
|
||||
|
||||
val inReplyToRootNostrEvent = inReplyToRelation.inReplyToRootNostrEventId?.let { database.nostrEventDao().getNostrEventById(it) }
|
||||
|
||||
val inReplyToRootProfilePublicKey = if (inReplyToRootNostrEvent == null) {
|
||||
eventIdsToSync.add(inReplyToRelation.inReplyToNostrEventId)
|
||||
|
||||
inReplyToRelation.inReplyToRootProfilePublicKey
|
||||
// Might need to save place holder...
|
||||
} else {
|
||||
inReplyToRootNostrEvent.pubKey
|
||||
}
|
||||
|
||||
val inReplyToProfile = inReplyToRootProfilePublicKey?.let { database.profileDao().getProfileByPublicKey(it) }
|
||||
|
||||
if (inReplyToRootProfilePublicKey != null && inReplyToProfile == null) {
|
||||
database.profileDao().insertPlaceholderProfile(
|
||||
Profile(
|
||||
publicKey = inReplyToRootProfilePublicKey,
|
||||
createdAt = GENESIS_AT,
|
||||
nostrEventId = nostrEvent.id, // Will get overwriting by sync,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
database.inReplyToRelationDao().upsert(
|
||||
inReplyToRelation.copy(
|
||||
inReplyToRootProfilePublicKey = inReplyToRootProfilePublicKey,
|
||||
inReplyToProfilePublicKey = inReplyToProfilePublicKey
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
nostrEvent.toZap()?.let { zap ->
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.Post
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedPost
|
||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalPost
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
|
||||
@Dao
|
||||
interface QuotedPostDao {
|
||||
@Insert
|
||||
suspend fun insert(quotedPost: QuotedPost)
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(quotedPost: QuotedPost)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedRelation
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
|
||||
@Dao
|
||||
interface QuotedRelationDao {
|
||||
@Query("SELECT * FROM QuotedRelation WHERE quotingNostrEventId = :quotingNostrEventId")
|
||||
fun getRepostByQuotingNostrEventId(quotingNostrEventId: String): QuotedRelation?
|
||||
|
||||
@Query("SELECT * FROM QuotedRelation WHERE quotedNostrEventId = :quotedNostrEventId")
|
||||
fun getRepostByQuotedNostrEventId(quotedNostrEventId: String): QuotedRelation?
|
||||
|
||||
@Insert
|
||||
suspend fun insert(quotedRelation: QuotedRelation)
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(quotedRelation: QuotedRelation)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.Repost
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface RepostDao {
|
||||
@Query("SELECT * FROM Repost")
|
||||
fun getAllReposts(): List<Repost>
|
||||
|
||||
@Query("SELECT * FROM Repost WHERE id = :id")
|
||||
fun getRepostById(id: String): Flow<Repost?>
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(repost: Repost)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.RepostedRelation
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
|
||||
@Dao
|
||||
interface RepostedRelationDao {
|
||||
@Query("SELECT * FROM RepostedRelation")
|
||||
fun getAllReposts(): List<RepostedRelation>
|
||||
|
||||
@Query("SELECT * FROM RepostedRelation WHERE repostingNostrEventId = :repostingNostrEventId")
|
||||
fun getRepostByRepostingId(repostingNostrEventId: String): RepostedRelation?
|
||||
|
||||
@Query("SELECT * FROM RepostedRelation WHERE repostedNostrEventId = :repostedNostrEventId")
|
||||
fun getRepostByRepostedId(repostedNostrEventId: String): RepostedRelation?
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(repostedRelation: RepostedRelation)
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.BroadcastableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.NostrEventEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.ProfilePublicKeyEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["profilePublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["inReplyToPostAuthorPublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// This might cause problems... but we gonna make the feed so cool if it works...
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["nostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// Support post replies
|
||||
ForeignKey(
|
||||
entity = Post::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["inReplyToPostId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
indices = [
|
||||
Index("profilePublicKey"),
|
||||
Index("nostrEventId"),
|
||||
Index("inReplyToPostId")
|
||||
],
|
||||
)
|
||||
data class InReplyToPost(
|
||||
@PrimaryKey
|
||||
val id: HexKey,
|
||||
|
||||
val inReplyToPostId: HexKey,
|
||||
val inReplyToPostTags: TagArray,
|
||||
val inReplyToPostCreatedAt: Instant,
|
||||
val inReplyToPostContent: String,
|
||||
val inReplyToPostAuthorPublicKey: HexKey,
|
||||
|
||||
val content: String,
|
||||
|
||||
override val nostrEventId: HexKey, // Might be a replaceable nostr event?
|
||||
override val profilePublicKey: HexKey,
|
||||
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = Clock.System.now(),
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val viewedAt: Instant? = null,
|
||||
override val deletedAt: Instant? = null,
|
||||
override val broadcastedAt: Instant? = null,
|
||||
): NostrEventEntity, ProfilePublicKeyEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as InReplyToPost
|
||||
|
||||
if (id != other.id) return false
|
||||
if (inReplyToPostId != other.inReplyToPostId) return false
|
||||
if (!inReplyToPostTags.contentDeepEquals(other.inReplyToPostTags)) return false
|
||||
if (inReplyToPostCreatedAt != other.inReplyToPostCreatedAt) return false
|
||||
if (inReplyToPostContent != other.inReplyToPostContent) return false
|
||||
if (inReplyToPostAuthorPublicKey != other.inReplyToPostAuthorPublicKey) return false
|
||||
if (content != other.content) return false
|
||||
if (nostrEventId != other.nostrEventId) return false
|
||||
if (profilePublicKey != other.profilePublicKey) return false
|
||||
if (createdAt != other.createdAt) return false
|
||||
if (updatedAt != other.updatedAt) return false
|
||||
if (savedAt != other.savedAt) return false
|
||||
if (viewedAt != other.viewedAt) return false
|
||||
if (deletedAt != other.deletedAt) return false
|
||||
if (broadcastedAt != other.broadcastedAt) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + inReplyToPostId.hashCode()
|
||||
result = 31 * result + inReplyToPostTags.contentDeepHashCode()
|
||||
result = 31 * result + inReplyToPostCreatedAt.hashCode()
|
||||
result = 31 * result + inReplyToPostContent.hashCode()
|
||||
result = 31 * result + inReplyToPostAuthorPublicKey.hashCode()
|
||||
result = 31 * result + content.hashCode()
|
||||
result = 31 * result + nostrEventId.hashCode()
|
||||
result = 31 * result + profilePublicKey.hashCode()
|
||||
result = 31 * result + createdAt.hashCode()
|
||||
result = 31 * result + updatedAt.hashCode()
|
||||
result = 31 * result + savedAt.hashCode()
|
||||
result = 31 * result + (viewedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (deletedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (broadcastedAt?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.BroadcastableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["inReplyToProfilePublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["inReplyToRootProfilePublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// This might cause problems... but we gonna make the feed so cool if it works...
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["replyingNostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["inReplyToNostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["inReplyToRootNostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
primaryKeys = ["replyingNostrEventId", "inReplyToNostrEventId"]
|
||||
)
|
||||
data class InReplyToRelation(
|
||||
val replyingNostrEventId: HexKey, // Might be a replaceable nostr event?
|
||||
|
||||
val inReplyToNostrEventId: HexKey,
|
||||
val inReplyToProfilePublicKey: HexKey?,
|
||||
|
||||
val inReplyToRootNostrEventId: HexKey?,
|
||||
val inReplyToRootProfilePublicKey: HexKey?,
|
||||
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = Clock.System.now(),
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val viewedAt: Instant? = null,
|
||||
override val deletedAt: Instant? = null,
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity {
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import kotlin.time.Instant
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["publicKey"],
|
||||
childColumns = ["mentionedPublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
@@ -26,10 +26,10 @@ import kotlin.time.Instant
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
primaryKeys = ["nostrEventId", "publicKey"]
|
||||
primaryKeys = ["nostrEventId", "mentionedPublicKey"]
|
||||
)
|
||||
data class Mention(
|
||||
val publicKey: HexKey,
|
||||
val mentionedPublicKey: HexKey,
|
||||
|
||||
val relayUrl: String? = null,
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UnsignedNostrEventEntity
|
||||
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.Index
|
||||
@@ -16,9 +17,12 @@ import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.firstTaggedEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.firstTaggedUser
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
|
||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.QAddressableTag
|
||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.QEventTag
|
||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.firstTaggedQuote
|
||||
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.utils.EventFactory
|
||||
@@ -37,8 +41,8 @@ import kotlin.time.Instant
|
||||
Index("kind"),
|
||||
Index("pubKey"),
|
||||
Index("quotedNostrEventId"),
|
||||
Index("rootNostrEventId"),
|
||||
Index("replyNostrEventId"),
|
||||
Index("inReplyToNostrEventId"),
|
||||
Index("inReplyToRootNostrEventId"),
|
||||
]
|
||||
)
|
||||
data class NostrEvent(
|
||||
@@ -51,12 +55,16 @@ data class NostrEvent(
|
||||
val sig: HexKey,
|
||||
|
||||
val quotedNostrEventId: HexKey? = null,
|
||||
val quotedAuthorPublicKey: HexKey? = null,
|
||||
|
||||
val rootNostrEventId: HexKey? = null,
|
||||
val replyNostrEventId: HexKey? = null,
|
||||
val inReplyToNostrEventId: HexKey? = null,
|
||||
val inReplyToAuthorPublicKey: HexKey? = null,
|
||||
|
||||
val taggedNostrEventId: HexKey? = null,
|
||||
val taggedNostrEventRelayUrl: String? = null,
|
||||
val inReplyToRootNostrEventId: HexKey? = null,
|
||||
val inReplyToRootAuthorPublicKey: HexKey? = null,
|
||||
|
||||
val repostedNostrEventId: HexKey? = null,
|
||||
val repostedAuthorPublicKey: HexKey? = null,
|
||||
|
||||
override val unsignedNostrEventId: Long? = null,
|
||||
|
||||
@@ -202,7 +210,7 @@ data class NostrEvent(
|
||||
return null
|
||||
}
|
||||
|
||||
fun toRepost(): Repost? = try {
|
||||
fun toRepostedRelation(): RepostedRelation? = try {
|
||||
if (kind == RepostEvent.KIND) {
|
||||
val repostEvent = EventFactory.create<RepostEvent>(
|
||||
id = id,
|
||||
@@ -215,17 +223,11 @@ data class NostrEvent(
|
||||
)
|
||||
|
||||
return repostEvent.containedPost()?.let { containedPost ->
|
||||
Repost(
|
||||
id = repostEvent.id,
|
||||
repostedPostId = containedPost.id,
|
||||
repostedPostTags = containedPost.tags,
|
||||
repostedPostContent = containedPost.content,
|
||||
repostedPostCreatedAt = Instant.fromEpochSeconds(containedPost.createdAt),
|
||||
content = containedPost.content,
|
||||
RepostedRelation(
|
||||
repostedNostrEventId = containedPost.id,
|
||||
repostedProfilePublicKey = containedPost.pubKey,
|
||||
|
||||
nostrEventId = id,
|
||||
profilePublicKey = repostEvent.pubKey,
|
||||
repostedPostAuthorPublicKey = containedPost.pubKey,
|
||||
repostingNostrEventId = repostEvent.id,
|
||||
|
||||
createdAt = Instant.fromEpochSeconds(repostEvent.createdAt),
|
||||
updatedAt = Instant.fromEpochSeconds(repostEvent.createdAt),
|
||||
@@ -240,6 +242,80 @@ data class NostrEvent(
|
||||
return null
|
||||
}
|
||||
|
||||
fun toQuotedRelation(): QuotedRelation? = try {
|
||||
if (kind == TextNoteEvent.KIND) {
|
||||
tags.firstTaggedQuote()?.let { taggedQuote ->
|
||||
when (taggedQuote) {
|
||||
is QEventTag -> {
|
||||
Triple(
|
||||
taggedQuote.eventId,
|
||||
taggedQuote.author,
|
||||
taggedQuote.relay,
|
||||
)
|
||||
}
|
||||
is QAddressableTag -> {
|
||||
Triple(
|
||||
taggedQuote.address.dTag,
|
||||
taggedQuote.address.pubKeyHex,
|
||||
taggedQuote.relay,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}?.let { quotedEventData ->
|
||||
|
||||
return QuotedRelation(
|
||||
quotedNostrEventId = quotedEventData.first,
|
||||
quotedProfilePublicKey = quotedEventData.second,
|
||||
|
||||
quotingNostrEventId = id,
|
||||
|
||||
createdAt = createdAt
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Get quoted event from content...
|
||||
|
||||
return null
|
||||
} catch (e: Throwable) {
|
||||
logger.e("Failed to return Repost: ", e)
|
||||
return null
|
||||
}
|
||||
|
||||
fun toInReplyToRelation(): InReplyToRelation? = try {
|
||||
if (kind == RepostEvent.KIND) {
|
||||
val textNoteEvent = EventFactory.create<TextNoteEvent>(
|
||||
id = id,
|
||||
pubKey = pubKey,
|
||||
createdAt = createdAt.epochSeconds,
|
||||
kind = kind,
|
||||
tags = tags,
|
||||
content = content,
|
||||
sig = sig
|
||||
)
|
||||
|
||||
|
||||
val rootReply = textNoteEvent.markedRoot()
|
||||
textNoteEvent.markedReply()?.let { replyTag ->
|
||||
|
||||
return InReplyToRelation(
|
||||
inReplyToNostrEventId = replyTag.eventId,
|
||||
inReplyToProfilePublicKey = replyTag.author,
|
||||
|
||||
inReplyToRootNostrEventId = rootReply?.eventId,
|
||||
inReplyToRootProfilePublicKey = rootReply?.author,
|
||||
|
||||
replyingNostrEventId = id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
} catch (e: Throwable) {
|
||||
logger.e("Failed to return Repost: ", e)
|
||||
return null
|
||||
}
|
||||
fun toZap(): Zap? = try {
|
||||
if (kind == LnZapEvent.KIND) {
|
||||
val zapEvent = EventFactory.create<LnZapEvent>(
|
||||
@@ -299,6 +375,58 @@ data class NostrEvent(
|
||||
// TODO: Check for unsupported kind
|
||||
val taggedEvent = event.firstTaggedEvent()
|
||||
|
||||
val quotedEvent = when (val taggedQuote = event.firstTaggedQuote()) {
|
||||
is QEventTag -> {
|
||||
Triple(
|
||||
taggedQuote.eventId,
|
||||
taggedQuote.author,
|
||||
taggedQuote.relay,
|
||||
)
|
||||
}
|
||||
is QAddressableTag -> {
|
||||
Triple(
|
||||
taggedQuote.address.dTag,
|
||||
taggedQuote.address.pubKeyHex,
|
||||
taggedQuote.relay,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
val repostedEvent = if (event.kind == RepostEvent.KIND) {
|
||||
val repostedEvent = event.taggedEvents().firstOrNull()
|
||||
when {
|
||||
(repostedEvent != null) -> {
|
||||
repostedEvent
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val (replyToRoot, replyTo) = if (event.kind == TextNoteEvent.KIND) {
|
||||
val textNoteEvent = TextNoteEvent(
|
||||
id = event.id,
|
||||
content = event.content,
|
||||
tags = event.tags,
|
||||
createdAt = event.createdAt,
|
||||
sig = event.sig,
|
||||
pubKey = event.pubKey
|
||||
)
|
||||
|
||||
Pair(
|
||||
textNoteEvent.markedRoot(),
|
||||
textNoteEvent.markedReply()
|
||||
)
|
||||
} else {
|
||||
Pair(
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
return NostrEvent(
|
||||
id = event.id,
|
||||
pubKey = event.pubKey,
|
||||
@@ -309,8 +437,17 @@ data class NostrEvent(
|
||||
unsignedNostrEventId = synchronizeNostrEventRequest?.unsignedNostrEventId,
|
||||
sig = event.sig,
|
||||
|
||||
taggedNostrEventId = taggedEvent?.eventId,
|
||||
taggedNostrEventRelayUrl = taggedEvent?.relay?.url,
|
||||
quotedNostrEventId = quotedEvent?.first,
|
||||
quotedAuthorPublicKey = quotedEvent?.second,
|
||||
|
||||
repostedNostrEventId = repostedEvent?.eventId,
|
||||
repostedAuthorPublicKey = repostedEvent?.author,
|
||||
|
||||
inReplyToRootNostrEventId = replyToRoot?.eventId,
|
||||
inReplyToRootAuthorPublicKey = replyToRoot?.author,
|
||||
|
||||
inReplyToNostrEventId = replyTo?.eventId,
|
||||
inReplyToAuthorPublicKey = replyTo?.author,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
return null
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.BroadcastableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.NostrEventEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.ProfilePublicKeyEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import ac.cord.auxiliary.compose.extensions.toFormattedTimeAndDateString
|
||||
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["profilePublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["quotedPostAuthorPublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// This might cause problems... but we gonna make the feed so cool if it works...
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["nostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// Support post replies
|
||||
ForeignKey(
|
||||
entity = Post::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["quotedPostId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
indices = [
|
||||
Index("profilePublicKey"),
|
||||
Index("nostrEventId"),
|
||||
Index("quotedPostId")
|
||||
],
|
||||
)
|
||||
data class QuotedPost(
|
||||
@PrimaryKey
|
||||
val id: HexKey,
|
||||
|
||||
val quotedPostId: HexKey,
|
||||
val quotedPostTags: TagArray,
|
||||
val quotedPostCreatedAt: Instant,
|
||||
val quotedPostContent: String,
|
||||
val quotedPostAuthorPublicKey: HexKey,
|
||||
|
||||
val content: String,
|
||||
|
||||
override val nostrEventId: HexKey, // Might be a replaceable nostr event?
|
||||
override val profilePublicKey: HexKey,
|
||||
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = Clock.System.now(),
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val viewedAt: Instant? = null,
|
||||
override val deletedAt: Instant? = null,
|
||||
override val broadcastedAt: Instant? = null,
|
||||
): NostrEventEntity, ProfilePublicKeyEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as QuotedPost
|
||||
|
||||
if (id != other.id) return false
|
||||
if (quotedPostId != other.quotedPostId) return false
|
||||
if (!quotedPostTags.contentDeepEquals(other.quotedPostTags)) return false
|
||||
if (quotedPostCreatedAt != other.quotedPostCreatedAt) return false
|
||||
if (quotedPostContent != other.quotedPostContent) return false
|
||||
if (quotedPostAuthorPublicKey != other.quotedPostAuthorPublicKey) return false
|
||||
if (content != other.content) return false
|
||||
if (nostrEventId != other.nostrEventId) return false
|
||||
if (profilePublicKey != other.profilePublicKey) return false
|
||||
if (createdAt != other.createdAt) return false
|
||||
if (updatedAt != other.updatedAt) return false
|
||||
if (savedAt != other.savedAt) return false
|
||||
if (viewedAt != other.viewedAt) return false
|
||||
if (deletedAt != other.deletedAt) return false
|
||||
if (broadcastedAt != other.broadcastedAt) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + quotedPostId.hashCode()
|
||||
result = 31 * result + quotedPostTags.contentDeepHashCode()
|
||||
result = 31 * result + quotedPostCreatedAt.hashCode()
|
||||
result = 31 * result + quotedPostContent.hashCode()
|
||||
result = 31 * result + quotedPostAuthorPublicKey.hashCode()
|
||||
result = 31 * result + content.hashCode()
|
||||
result = 31 * result + nostrEventId.hashCode()
|
||||
result = 31 * result + profilePublicKey.hashCode()
|
||||
result = 31 * result + createdAt.hashCode()
|
||||
result = 31 * result + updatedAt.hashCode()
|
||||
result = 31 * result + savedAt.hashCode()
|
||||
result = 31 * result + (viewedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (deletedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (broadcastedAt?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderNotePreview() {
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(12.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
|
||||
// TODO ProfileAvatar(
|
||||
// profile = profile,
|
||||
// publicKey = pubKey
|
||||
// )
|
||||
|
||||
// Column(
|
||||
// modifier = Modifier.weight(1f)
|
||||
// ) {
|
||||
// Text(
|
||||
// text = profile?.displayName ?: profile?.userName ?: nostrEvent.pubKey,
|
||||
// style = MaterialTheme.typography.labelLarge
|
||||
// )
|
||||
//
|
||||
// profile?.nip05?.let {
|
||||
// Text(
|
||||
// text = profile.nip05 ?: "",
|
||||
// style = MaterialTheme.typography.labelMedium
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
Text(
|
||||
text = "Loading Profile information"
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth().padding(
|
||||
horizontal = 20.dp
|
||||
),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
textAlign = TextAlign.Start,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
text = content
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(20.dp),
|
||||
horizontalArrangement = Arrangement.Start
|
||||
) {
|
||||
Text(
|
||||
text = createdAt.toFormattedTimeAndDateString(),
|
||||
style = MaterialTheme.typography.labelSmall
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.BroadcastableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["quotedProfilePublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// This might cause problems... but we gonna make the feed so cool if it works...
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["quotingNostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// Support post replies
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["quotedNostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
primaryKeys = [
|
||||
"quotingNostrEventId", "quotedNostrEventId"
|
||||
]
|
||||
)
|
||||
data class QuotedRelation(
|
||||
val quotingNostrEventId: HexKey,
|
||||
|
||||
val quotedNostrEventId: HexKey,
|
||||
val quotedProfilePublicKey: HexKey?,
|
||||
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = createdAt,
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val viewedAt: Instant? = null,
|
||||
override val deletedAt: Instant? = null,
|
||||
override val broadcastedAt: Instant? = null,
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity {
|
||||
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.BroadcastableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.NostrEventEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.ProfilePublicKeyEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["profilePublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["repostedPostAuthorPublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// This might cause problems... but we gonna make the feed so cool if it works...
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["nostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// Support post replies
|
||||
ForeignKey(
|
||||
entity = Post::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["repostedPostId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
indices = [
|
||||
Index("profilePublicKey"),
|
||||
Index("nostrEventId"),
|
||||
Index("repostedPostId")
|
||||
],
|
||||
)
|
||||
data class Repost(
|
||||
@PrimaryKey
|
||||
val id: HexKey,
|
||||
|
||||
val repostedPostId: HexKey,
|
||||
val repostedPostTags: TagArray,
|
||||
val repostedPostCreatedAt: Instant,
|
||||
val repostedPostContent: String,
|
||||
val repostedPostAuthorPublicKey: HexKey,
|
||||
|
||||
val content: String,
|
||||
|
||||
override val nostrEventId: HexKey, // Might be a replaceable nostr event?
|
||||
override val profilePublicKey: HexKey,
|
||||
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = Clock.System.now(),
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val viewedAt: Instant? = null,
|
||||
override val deletedAt: Instant? = null,
|
||||
override val broadcastedAt: Instant? = null,
|
||||
): NostrEventEntity, ProfilePublicKeyEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as Repost
|
||||
|
||||
if (id != other.id) return false
|
||||
if (repostedPostId != other.repostedPostId) return false
|
||||
if (repostedPostAuthorPublicKey != other.repostedPostAuthorPublicKey) return false
|
||||
if (!repostedPostTags.contentDeepEquals(other.repostedPostTags)) return false
|
||||
if (content != other.content) return false
|
||||
if (nostrEventId != other.nostrEventId) return false
|
||||
if (profilePublicKey != other.profilePublicKey) return false
|
||||
if (createdAt != other.createdAt) return false
|
||||
if (updatedAt != other.updatedAt) return false
|
||||
if (savedAt != other.savedAt) return false
|
||||
if (viewedAt != other.viewedAt) return false
|
||||
if (deletedAt != other.deletedAt) return false
|
||||
if (broadcastedAt != other.broadcastedAt) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + repostedPostId.hashCode()
|
||||
result = 31 * result + repostedPostAuthorPublicKey.hashCode()
|
||||
result = 31 * result + repostedPostTags.contentDeepHashCode()
|
||||
result = 31 * result + content.hashCode()
|
||||
result = 31 * result + nostrEventId.hashCode()
|
||||
result = 31 * result + profilePublicKey.hashCode()
|
||||
result = 31 * result + createdAt.hashCode()
|
||||
result = 31 * result + updatedAt.hashCode()
|
||||
result = 31 * result + savedAt.hashCode()
|
||||
result = 31 * result + (viewedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (deletedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (broadcastedAt?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.BroadcastableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["repostedProfilePublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["repostedNostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
// This might cause problems... but we gonna make the feed so cool if it works...
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["repostingNostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
primaryKeys = [
|
||||
"repostingNostrEventId", "repostedNostrEventId"
|
||||
]
|
||||
)
|
||||
data class RepostedRelation(
|
||||
val repostingNostrEventId: HexKey,
|
||||
|
||||
val repostedNostrEventId: HexKey,
|
||||
val repostedProfilePublicKey: HexKey?,
|
||||
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = Clock.System.now(),
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val viewedAt: Instant? = null,
|
||||
override val deletedAt: Instant? = null,
|
||||
override val broadcastedAt: Instant? = null,
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity {
|
||||
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package ac.cord.auxiliary.compose.database.model.intermdiate
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.InReplyToPost
|
||||
import ac.cord.auxiliary.compose.database.model.InReplyToRelation
|
||||
import ac.cord.auxiliary.compose.database.model.Mention
|
||||
import ac.cord.auxiliary.compose.database.model.NostrEvent
|
||||
import ac.cord.auxiliary.compose.database.model.Profile
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedPost
|
||||
import ac.cord.auxiliary.compose.database.model.Repost
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedRelation
|
||||
import ac.cord.auxiliary.compose.database.model.RepostedRelation
|
||||
import ac.cord.auxiliary.compose.extensions.toFormattedTimeAndDateString
|
||||
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -22,6 +22,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.Junction
|
||||
import androidx.room.Relation
|
||||
|
||||
@@ -36,32 +37,59 @@ data class LocalNostrEvent(
|
||||
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "nostrEventId"
|
||||
entityColumn = "repostingNostrEventId"
|
||||
)
|
||||
val repost: Repost? = null,
|
||||
val repostedRelation: RepostedRelation? = null,
|
||||
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "nostrEventId"
|
||||
entityColumn = "quotingNostrEventId"
|
||||
)
|
||||
val quotedPost: QuotedPost? = null,
|
||||
val quotedRelation: QuotedRelation? = null,
|
||||
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "nostrEventId"
|
||||
entityColumn = "id",
|
||||
associateBy = Junction(
|
||||
value = QuotedRelation::class,
|
||||
parentColumn = "quotingNostrEventId",
|
||||
entityColumn = "quotedNostrEventId"
|
||||
)
|
||||
)
|
||||
val inReplyToNostrEvent: InReplyToPost? = null,
|
||||
val quotedNostrEvent: NostrEvent? = null,
|
||||
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "publicKey",
|
||||
associateBy = Junction(
|
||||
value = QuotedRelation::class,
|
||||
parentColumn = "quotingNostrEventId",
|
||||
entityColumn = "quotedProfilePublicKey"
|
||||
)
|
||||
)
|
||||
val quotedAuthorProfile: Profile? = null,
|
||||
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "replyingNostrEventId"
|
||||
)
|
||||
val inReplyToNostrEvent: InReplyToRelation? = null,
|
||||
|
||||
// @Relation(
|
||||
// parentColumn = "id",
|
||||
// entityColumn = "nostrEventId",
|
||||
// associateBy = Junction(
|
||||
// value = Mention::class,
|
||||
// parentColumn = "mentionedPublicKey",
|
||||
// entityColumn = "mentionedPublicKey"
|
||||
// )
|
||||
// )
|
||||
// val mentionedProfiles: List<Profile> = emptyList()
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "nostrEventId",
|
||||
associateBy = Junction(
|
||||
value = Mention::class,
|
||||
parentColumn = "publicKey",
|
||||
entityColumn = "publicKey"
|
||||
)
|
||||
)
|
||||
val mentionedProfiles: List<Profile> = emptyList()
|
||||
val mentions: List<Mention> = emptyList()
|
||||
) {
|
||||
@Composable
|
||||
fun RenderNotePreview() {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package ac.cord.auxiliary.compose.database.model.intermdiate
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.InReplyToRelation
|
||||
import ac.cord.auxiliary.compose.database.model.Mention
|
||||
import ac.cord.auxiliary.compose.database.model.NostrEvent
|
||||
import ac.cord.auxiliary.compose.database.model.Profile
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedRelation
|
||||
import ac.cord.auxiliary.compose.database.model.RepostedRelation
|
||||
import ac.cord.auxiliary.compose.extensions.toFormattedTimeAndDateString
|
||||
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Junction
|
||||
import androidx.room.Relation
|
||||
|
||||
data class LocalQuotedNostrEvent(
|
||||
@Embedded val nostrEvent: NostrEvent,
|
||||
|
||||
@Relation(
|
||||
parentColumn = "pubKey",
|
||||
entityColumn = "publicKey"
|
||||
)
|
||||
val profile: Profile?,
|
||||
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "nostrEventId",
|
||||
associateBy = Junction(
|
||||
value = Mention::class,
|
||||
parentColumn = "publicKey",
|
||||
entityColumn = "publicKey"
|
||||
)
|
||||
)
|
||||
val mentionedProfiles: List<Profile> = emptyList()
|
||||
) {
|
||||
@Composable
|
||||
fun RenderNotePreview() {
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(12.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val profile = profile
|
||||
|
||||
ProfileAvatar(
|
||||
profile = profile,
|
||||
publicKey = nostrEvent.pubKey
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
text = profile?.displayName ?: profile?.userName ?: nostrEvent.pubKey,
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
|
||||
profile?.nip05?.let {
|
||||
Text(
|
||||
text = profile.nip05 ?: "",
|
||||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth().padding(
|
||||
horizontal = 20.dp
|
||||
),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
textAlign = TextAlign.Start,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
text = nostrEvent.content
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(20.dp),
|
||||
horizontalArrangement = Arrangement.Start
|
||||
) {
|
||||
Text(
|
||||
text = nostrEvent.createdAt.toFormattedTimeAndDateString(),
|
||||
style = MaterialTheme.typography.labelSmall
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,5 @@ package ac.cord.auxiliary.compose.database.model.traits
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
|
||||
interface ProfilePublicKeyEntity {
|
||||
val profilePublicKey: HexKey
|
||||
val profilePublicKey: HexKey?
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
@@ -41,9 +40,9 @@ internal fun QuotedAddressableNote(
|
||||
// }
|
||||
// }
|
||||
|
||||
if (localNostrEvent?.quotedPost != null) {
|
||||
if (localNostrEvent?.quotedRelation != null) {
|
||||
QuotedNote(
|
||||
quotedPost = localNostrEvent.quotedPost,
|
||||
quotedNostrEvent = localNostrEvent.quotedRelation,
|
||||
onNoteClick = onNoteClick,
|
||||
noteActions = noteActions
|
||||
)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package ac.cord.auxiliary.compose.ui.composable.widgets.content
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedPost
|
||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
|
||||
import ac.cord.auxiliary.compose.ui.composable.widgets.content.Helpers.isGalleryEvent
|
||||
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
|
||||
import ac.cord.auxiliary.compose.database.model.NostrEvent
|
||||
import ac.cord.auxiliary.compose.database.model.Profile
|
||||
import ac.cord.auxiliary.compose.database.model.QuotedRelation
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -19,16 +17,14 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun QuotedNote(
|
||||
quotedPost: QuotedPost? = null,
|
||||
quotedNostrEvent: QuotedRelation? = null,
|
||||
quotedProfile: Profile? = null,
|
||||
relayHints: List<String> = emptyList(),
|
||||
onNoteClick: ((String) -> Unit)? = null,
|
||||
noteActions: NoteActions? = null
|
||||
@@ -54,7 +50,7 @@ fun QuotedNote(
|
||||
// }
|
||||
// }
|
||||
|
||||
if (quotedPost != null && noteActions != null) {
|
||||
if (quotedNostrEvent != null && noteActions != null) {
|
||||
// Full rendering with all interactive features
|
||||
|
||||
Surface(
|
||||
@@ -65,9 +61,10 @@ fun QuotedNote(
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 6.dp)
|
||||
) {
|
||||
quotedPost.RenderNotePreview()
|
||||
Text("Quote render coming soon")
|
||||
// quotedNostrEvent.RenderNotePreview()
|
||||
}
|
||||
} else if (quotedPost != null) {
|
||||
} else if (quotedNostrEvent != null) {
|
||||
// Simple fallback rendering (no noteActions available)
|
||||
Surface(
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
@@ -77,11 +74,12 @@ fun QuotedNote(
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 6.dp)
|
||||
.then(
|
||||
if (effectiveNoteClick != null) Modifier.clickable { effectiveNoteClick(quotedPost.nostrEventId) }
|
||||
if (effectiveNoteClick != null) Modifier.clickable { effectiveNoteClick(quotedNostrEvent.quotedNostrEventId) }
|
||||
else Modifier
|
||||
)
|
||||
) {
|
||||
quotedPost.RenderNotePreview()
|
||||
Text("Quote render coming soon")
|
||||
// quotedPost.RenderNotePreview()
|
||||
}
|
||||
} else {
|
||||
// Loading state
|
||||
|
||||
@@ -101,11 +101,11 @@ fun RichContent(
|
||||
val profileNames = remember(profilePubkeys) {
|
||||
// TODO: Get these from taggedUsers...
|
||||
val names = mutableMapOf<String, String>()
|
||||
for (pubkey in profilePubkeys) {
|
||||
val profile = localNostrEvent.mentionedProfiles.find { taggedAuthor -> taggedAuthor.publicKey == pubkey }
|
||||
names[pubkey] = profile?.humanReadableNameOrPubkey()
|
||||
?: "${pubkey.take(8)}...${pubkey.takeLast(4)}"
|
||||
}
|
||||
// TODO for (pubkey in profilePubkeys) {
|
||||
// val profile = localNostrEvent.mentionedProfiles.find { taggedAuthor -> taggedAuthor.publicKey == pubkey }
|
||||
// names[pubkey] = profile?.humanReadableNameOrPubkey()
|
||||
// ?: "${pubkey.take(8)}...${pubkey.takeLast(4)}"
|
||||
// }
|
||||
names
|
||||
}
|
||||
// TODO Queue fetches for any missing profiles
|
||||
@@ -263,9 +263,9 @@ fun RichContent(
|
||||
LinkPreview(url = segment.url)
|
||||
}
|
||||
is ContentSegment.NostrNoteSegment -> {
|
||||
if (localNostrEvent.quotedPost != null) {
|
||||
if (localNostrEvent.quotedRelation != null) {
|
||||
QuotedNote(
|
||||
quotedPost = localNostrEvent.quotedPost,
|
||||
quotedNostrEvent = localNostrEvent.quotedRelation,
|
||||
relayHints = segment.relayHints,
|
||||
onNoteClick = onNoteClick,
|
||||
noteActions = noteActions
|
||||
|
||||
@@ -4,7 +4,6 @@ import ac.cord.auxiliary.compose.database.model.NostrEvent
|
||||
import ac.cord.auxiliary.compose.database.model.Profile
|
||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
|
||||
import ac.cord.auxiliary.compose.extensions.toFormattedTimeAndDateString
|
||||
import ac.cord.auxiliary.compose.ui.composable.widgets.content.RichContent
|
||||
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
|
||||
import ac.cord.auxiliary.compose.ui.theme.AuxTheme
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -62,7 +61,7 @@ fun LocalNostrEvent.ListView(
|
||||
style = MaterialTheme.typography.labelSmall)
|
||||
}
|
||||
|
||||
if (repost != null) {
|
||||
if (repostedRelation != null) {
|
||||
TextNoteFeedItem(
|
||||
localNostrEvent = this@ListView,
|
||||
onNavigateToEvent = onNavigateToEvent
|
||||
@@ -110,7 +109,7 @@ private fun TextNoteFeedItem(
|
||||
onNavigateToEvent: (HexKey) -> Unit
|
||||
) {
|
||||
val nostrEvent = localNostrEvent.nostrEvent
|
||||
if (localNostrEvent.repost != null) {
|
||||
if (localNostrEvent.repostedRelation != null) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(
|
||||
horizontal = 20.dp
|
||||
@@ -127,11 +126,11 @@ private fun TextNoteFeedItem(
|
||||
Text(
|
||||
modifier = Modifier.clickable(
|
||||
onClick = {
|
||||
onNavigateToEvent.invoke(localNostrEvent.repost.repostedPostId)
|
||||
onNavigateToEvent.invoke(localNostrEvent.repostedRelation.repostedNostrEventId)
|
||||
}
|
||||
),
|
||||
style = MaterialTheme.typography.labelLargeEmphasized,
|
||||
text = localNostrEvent.repost.repostedPostAuthorPublicKey ?: "loading information..."
|
||||
text = localNostrEvent.repostedRelation.repostedProfilePublicKey ?: "loading information..."
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -178,9 +177,12 @@ private fun TextNoteFeedItem(
|
||||
}
|
||||
|
||||
// TODO: RichContent here...
|
||||
RichContent(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
localNostrEvent = localNostrEvent,
|
||||
// RichContent(
|
||||
// modifier = Modifier.fillMaxWidth(),
|
||||
// localNostrEvent = localNostrEvent,
|
||||
// )
|
||||
Text(
|
||||
text = localNostrEvent.nostrEvent.content
|
||||
)
|
||||
|
||||
LazyRow(
|
||||
@@ -250,10 +252,6 @@ private fun EventListViewPreview() {
|
||||
nostrEventId = "referenced",
|
||||
displayName = "Frank Talk"
|
||||
),
|
||||
repost = null,
|
||||
quotedPost = null,
|
||||
inReplyToNostrEvent = null,
|
||||
mentionedProfiles = emptyList()
|
||||
).ListView(
|
||||
onNavigateToEvent = {}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user