@@ -68,7 +68,7 @@ func render_blocks(blocks: [Block]) -> String {
|
|||||||
case .text(let txt):
|
case .text(let txt):
|
||||||
return str + txt
|
return str + txt
|
||||||
case .hashtag(let htag):
|
case .hashtag(let htag):
|
||||||
return "#" + htag
|
return str + "#" + htag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,6 +236,9 @@ func make_post_tags(post_blocks: [PostBlock], tags: [[String]]) -> PostTags {
|
|||||||
let block = Block.mention(mention)
|
let block = Block.mention(mention)
|
||||||
blocks.append(block)
|
blocks.append(block)
|
||||||
}
|
}
|
||||||
|
case .hashtag(let hashtag):
|
||||||
|
new_tags.append(["hashtag", hashtag])
|
||||||
|
blocks.append(.hashtag(hashtag))
|
||||||
case .text(let txt):
|
case .text(let txt):
|
||||||
blocks.append(Block.text(txt))
|
blocks.append(Block.text(txt))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ func parse_post_blocks(content: String) -> [PostBlock] {
|
|||||||
blocks.append(parse_post_textblock(str: p.str, from: starting_from, to: pre_mention))
|
blocks.append(parse_post_textblock(str: p.str, from: starting_from, to: pre_mention))
|
||||||
blocks.append(.ref(reference))
|
blocks.append(.ref(reference))
|
||||||
starting_from = p.pos
|
starting_from = p.pos
|
||||||
|
} else if let hashtag = parse_hashtag(p) {
|
||||||
|
blocks.append(parse_post_textblock(str: p.str, from: starting_from, to: pre_mention))
|
||||||
|
blocks.append(.hashtag(hashtag))
|
||||||
|
starting_from = p.pos
|
||||||
} else {
|
} else {
|
||||||
p.pos += 1
|
p.pos += 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import Foundation
|
|||||||
enum PostBlock {
|
enum PostBlock {
|
||||||
case text(String)
|
case text(String)
|
||||||
case ref(ReferencedId)
|
case ref(ReferencedId)
|
||||||
|
case hashtag(String)
|
||||||
|
|
||||||
var is_text: Bool {
|
var is_text: Bool {
|
||||||
if case .text = self {
|
if case .text = self {
|
||||||
@@ -18,6 +19,13 @@ enum PostBlock {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var is_hashtag: Bool {
|
||||||
|
if case .hashtag = self {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var is_ref: Bool {
|
var is_ref: Bool {
|
||||||
if case .ref = self {
|
if case .ref = self {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import Foundation
|
|||||||
class SearchModel: ObservableObject {
|
class SearchModel: ObservableObject {
|
||||||
@Published var events: [NostrEvent] = []
|
@Published var events: [NostrEvent] = []
|
||||||
let pool: RelayPool
|
let pool: RelayPool
|
||||||
let search: NostrFilter
|
var search: NostrFilter
|
||||||
let sub_id = UUID().description
|
let sub_id = UUID().description
|
||||||
|
|
||||||
init(pool: RelayPool, search: NostrFilter) {
|
init(pool: RelayPool, search: NostrFilter) {
|
||||||
@@ -20,15 +20,15 @@ class SearchModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func subscribe() {
|
func subscribe() {
|
||||||
// since 2 month
|
// since 1 month
|
||||||
var filter = NostrFilter.copy(from: search)
|
search.since = Int64(Date.now.timeIntervalSince1970) - 2629800 * 1
|
||||||
filter.since = Int64(Date.now.timeIntervalSince1970) - 2629800 * 2
|
search.kinds = [1,5,7]
|
||||||
|
|
||||||
//likes_filter.ids = ref_events.referenced_ids!
|
//likes_filter.ids = ref_events.referenced_ids!
|
||||||
|
|
||||||
print("subscribing to search '\(filter)' with sub_id \(sub_id)")
|
print("subscribing to search '\(search)' with sub_id \(sub_id)")
|
||||||
pool.register_handler(sub_id: sub_id, handler: handle_event)
|
pool.register_handler(sub_id: sub_id, handler: handle_event)
|
||||||
pool.send(.subscribe(.init(filters: [filter], sub_id: sub_id)))
|
pool.send(.subscribe(.init(filters: [search], sub_id: sub_id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func unsubscribe() {
|
func unsubscribe() {
|
||||||
@@ -37,6 +37,10 @@ class SearchModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func add_event(_ ev: NostrEvent) {
|
func add_event(_ ev: NostrEvent) {
|
||||||
|
if !event_matches_filter(ev, filter: search) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if insert_uniq_sorted_event(events: &self.events, new_ev: ev) {
|
if insert_uniq_sorted_event(events: &self.events, new_ev: ev) {
|
||||||
objectWillChange.send()
|
objectWillChange.send()
|
||||||
}
|
}
|
||||||
@@ -51,6 +55,23 @@ class SearchModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func event_matches_hashtag(_ ev: NostrEvent, hashtags: [String]) -> Bool {
|
||||||
|
for tag in ev.tags {
|
||||||
|
if tag.count >= 2 && tag[0] == "hashtag" {
|
||||||
|
if hashtags.contains(tag[1]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func event_matches_filter(_ ev: NostrEvent, filter: NostrFilter) -> Bool {
|
||||||
|
if let hashtags = filter.hashtag {
|
||||||
|
return event_matches_hashtag(ev, hashtags: hashtags)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func handle_subid_event(pool: RelayPool, sub_id: String, relay_id: String, ev: NostrConnectionEvent, handle: (NostrEvent) -> ()) {
|
func handle_subid_event(pool: RelayPool, sub_id: String, relay_id: String, ev: NostrConnectionEvent, handle: (NostrEvent) -> ()) {
|
||||||
switch ev {
|
switch ev {
|
||||||
|
|||||||
@@ -10,17 +10,31 @@ import SwiftUI
|
|||||||
struct SearchView: View {
|
struct SearchView: View {
|
||||||
let appstate: DamusState
|
let appstate: DamusState
|
||||||
@StateObject var search: SearchModel
|
@StateObject var search: SearchModel
|
||||||
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TimelineView(events: $search.events, damus: appstate)
|
TimelineView(events: $search.events, damus: appstate)
|
||||||
.padding([.leading, .trailing], 6)
|
.navigationBarTitle(describe_search(search.search))
|
||||||
.onAppear() {
|
.padding([.leading, .trailing], 6)
|
||||||
search.subscribe()
|
.onReceive(handle_notify(.switched_timeline)) { obj in
|
||||||
}
|
dismiss()
|
||||||
.onDisappear() {
|
}
|
||||||
search.unsubscribe()
|
.onAppear() {
|
||||||
|
search.subscribe()
|
||||||
|
}
|
||||||
|
.onDisappear() {
|
||||||
|
search.unsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func describe_search(_ filter: NostrFilter) -> String {
|
||||||
|
if let hashtags = filter.hashtag {
|
||||||
|
if hashtags.count >= 1 {
|
||||||
|
return "#" + hashtags[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return "Search"
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -71,6 +71,21 @@ class damusTests: XCTestCase {
|
|||||||
XCTAssertEqual(parsed.count, 0)
|
XCTAssertEqual(parsed.count, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testMakeHashtagPost() {
|
||||||
|
let privkey = "d05f5fcceef3e4529703f62a29222d6ee2d1b7bf1f24729b5e01df7c633cec8a"
|
||||||
|
let pubkey = "6e59d3b78b1c1490a6489c94405873b57d8ef398a830ae5e39608f4107e9a790"
|
||||||
|
let post = NostrPost(content: "#damus some content #bitcoin derp", references: [])
|
||||||
|
let ev = post_to_event(post: post, privkey: privkey, pubkey: pubkey)
|
||||||
|
|
||||||
|
XCTAssertEqual(ev.tags.count, 2)
|
||||||
|
XCTAssertEqual(ev.content, "#damus some content #bitcoin derp")
|
||||||
|
XCTAssertEqual(ev.tags[0][0], "hashtag")
|
||||||
|
XCTAssertEqual(ev.tags[0][1], "damus")
|
||||||
|
XCTAssertEqual(ev.tags[1][0], "hashtag")
|
||||||
|
XCTAssertEqual(ev.tags[1][1], "bitcoin")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func testParseHashtag() {
|
func testParseHashtag() {
|
||||||
let parsed = parse_mentions(content: "some hashtag #bitcoin derp", tags: [])
|
let parsed = parse_mentions(content: "some hashtag #bitcoin derp", tags: [])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user