@@ -51,7 +51,6 @@ struct ContentView: View {
|
|||||||
@State var is_profile_open: Bool = false
|
@State var is_profile_open: Bool = false
|
||||||
@State var last_event_of_kind: [String: [Int: NostrEvent]] = [:]
|
@State var last_event_of_kind: [String: [Int: NostrEvent]] = [:]
|
||||||
@State var has_events: [String: ()] = [:]
|
@State var has_events: [String: ()] = [:]
|
||||||
@State var has_friend_event: [String: ()] = [:]
|
|
||||||
@State var new_notifications: Bool = false
|
@State var new_notifications: Bool = false
|
||||||
@State var event: NostrEvent? = nil
|
@State var event: NostrEvent? = nil
|
||||||
@State var events: [NostrEvent] = []
|
@State var events: [NostrEvent] = []
|
||||||
@@ -265,7 +264,7 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.onReceive(handle_notify(.boost)) { notif in
|
.onReceive(handle_notify(.boost)) { notif in
|
||||||
let ev = notif.object as! NostrEvent
|
let ev = notif.object as! NostrEvent
|
||||||
let boost = make_boost_event(ev, privkey: privkey, pubkey: pubkey)
|
let boost = make_boost_event(pubkey: pubkey, privkey: privkey, boosted: ev)
|
||||||
self.damus?.pool.send(.event(boost))
|
self.damus?.pool.send(.event(boost))
|
||||||
}
|
}
|
||||||
.onReceive(handle_notify(.open_thread)) { obj in
|
.onReceive(handle_notify(.open_thread)) { obj in
|
||||||
@@ -277,13 +276,14 @@ struct ContentView: View {
|
|||||||
let ev = notif.object as! NostrEvent
|
let ev = notif.object as! NostrEvent
|
||||||
self.active_sheet = .reply(ev)
|
self.active_sheet = .reply(ev)
|
||||||
}
|
}
|
||||||
|
.onReceive(handle_notify(.boost)) { boost in
|
||||||
|
let ev = boost.object as! NostrEvent
|
||||||
|
let boost_ev = make_boost_event(pubkey: pubkey, privkey: privkey, boosted: ev)
|
||||||
|
self.damus?.pool.send(.event(boost_ev))
|
||||||
|
}
|
||||||
.onReceive(handle_notify(.like)) { like in
|
.onReceive(handle_notify(.like)) { like in
|
||||||
let ev = like.object as! NostrEvent
|
let ev = like.object as! NostrEvent
|
||||||
guard let like_ev = make_like_event(pubkey: pubkey, liked: ev) else {
|
let like_ev = make_like_event(pubkey: pubkey, privkey: privkey, liked: ev)
|
||||||
return
|
|
||||||
}
|
|
||||||
like_ev.calculate_id()
|
|
||||||
like_ev.sign(privkey: privkey)
|
|
||||||
self.damus?.pool.send(.event(like_ev))
|
self.damus?.pool.send(.event(like_ev))
|
||||||
}
|
}
|
||||||
.onReceive(handle_notify(.broadcast_event)) { obj in
|
.onReceive(handle_notify(.broadcast_event)) { obj in
|
||||||
@@ -390,8 +390,28 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handle_boost_event(_ ev: NostrEvent) {
|
func handle_boost_event(_ ev: NostrEvent) {
|
||||||
|
var boost_ev_id = ev.last_refid()?.ref_id
|
||||||
|
|
||||||
//damus!.boosts.add_event(ev)
|
// CHECK SIGS ON THESE
|
||||||
|
if var inner_ev = ev.inner_event {
|
||||||
|
boost_ev_id = inner_ev.id
|
||||||
|
|
||||||
|
if inner_ev.kind == 1 {
|
||||||
|
handle_text_event(ev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let e = boost_ev_id else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch damus!.boosts.add_event(ev, target: e) {
|
||||||
|
case .already_counted:
|
||||||
|
break
|
||||||
|
case .success(let n):
|
||||||
|
let boosted = Counted(event: ev, id: e, total: n)
|
||||||
|
notify(.boosted, boosted)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle_like_event(_ ev: NostrEvent) {
|
func handle_like_event(_ ev: NostrEvent) {
|
||||||
@@ -403,10 +423,10 @@ struct ContentView: View {
|
|||||||
// CHECK SIGS ON THESE
|
// CHECK SIGS ON THESE
|
||||||
|
|
||||||
switch damus!.likes.add_event(ev, target: e.ref_id) {
|
switch damus!.likes.add_event(ev, target: e.ref_id) {
|
||||||
case .user_already_liked:
|
case .already_counted:
|
||||||
break
|
break
|
||||||
case .success(let n):
|
case .success(let n):
|
||||||
let liked = Liked(like: ev, id: e.ref_id, total: n)
|
let liked = Counted(event: ev, id: e.ref_id, total: n)
|
||||||
notify(.liked, liked)
|
notify(.liked, liked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -484,12 +504,12 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handle_friend_event(_ ev: NostrEvent) {
|
func handle_friend_event(_ ev: NostrEvent) {
|
||||||
if has_friend_event[ev.id] != nil || !is_friend_event(ev) {
|
if !is_friend_event(ev) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !insert_uniq_sorted_event(events: &self.friend_events, new_ev: ev, cmp: { $0.created_at > $1.created_at } ) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.has_friend_event[ev.id] = ()
|
|
||||||
self.friend_events.append(ev)
|
|
||||||
self.friend_events = self.friend_events.sorted { $0.created_at > $1.created_at }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle_text_event(_ ev: NostrEvent) {
|
func handle_text_event(_ ev: NostrEvent) {
|
||||||
@@ -497,8 +517,9 @@ struct ContentView: View {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.events.append(ev)
|
if !insert_uniq_sorted_event(events: &self.events, new_ev: ev, cmp: { $0.created_at > $1.created_at }) {
|
||||||
self.events = self.events.sorted { $0.created_at > $1.created_at }
|
return
|
||||||
|
}
|
||||||
|
|
||||||
handle_friend_event(ev)
|
handle_friend_event(ev)
|
||||||
|
|
||||||
@@ -521,6 +542,8 @@ struct ContentView: View {
|
|||||||
handle_text_event(ev)
|
handle_text_event(ev)
|
||||||
} else if ev.kind == 0 {
|
} else if ev.kind == 0 {
|
||||||
handle_metadata_event(ev)
|
handle_metadata_event(ev)
|
||||||
|
} else if ev.kind == 6 {
|
||||||
|
handle_boost_event(ev)
|
||||||
} else if ev.kind == 7 {
|
} else if ev.kind == 7 {
|
||||||
handle_like_event(ev)
|
handle_like_event(ev)
|
||||||
} else if ev.kind == 3 {
|
} else if ev.kind == 3 {
|
||||||
@@ -708,15 +731,6 @@ func save_last_notified(_ ev: NostrEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func make_boost_event(_ ev: NostrEvent, privkey: String, pubkey: String) -> NostrEvent {
|
|
||||||
let boost = NostrEvent(content: "", pubkey: pubkey, kind: 6, tags: [["e", ev.id]])
|
|
||||||
boost.calculate_id()
|
|
||||||
boost.sign(privkey: privkey)
|
|
||||||
return boost
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func get_like_pow() -> [String] {
|
func get_like_pow() -> [String] {
|
||||||
return ["00000"] // 20 bits
|
return ["00000"] // 20 bits
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ class ActionBarModel: ObservableObject {
|
|||||||
@Published var our_like: NostrEvent?
|
@Published var our_like: NostrEvent?
|
||||||
@Published var our_boost: NostrEvent?
|
@Published var our_boost: NostrEvent?
|
||||||
@Published var likes: Int
|
@Published var likes: Int
|
||||||
|
@Published var boosts: Int
|
||||||
|
|
||||||
init(likes: Int, our_like: NostrEvent?, our_boost: NostrEvent?) {
|
init(likes: Int, boosts: Int, our_like: NostrEvent?, our_boost: NostrEvent?) {
|
||||||
self.likes = likes
|
self.likes = likes
|
||||||
|
self.boosts = boosts
|
||||||
self.our_like = our_like
|
self.our_like = our_like
|
||||||
self.our_boost = our_boost
|
self.our_boost = our_boost
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ class EventCounter {
|
|||||||
var our_events: [String: NostrEvent] = [:]
|
var our_events: [String: NostrEvent] = [:]
|
||||||
var our_pubkey: String
|
var our_pubkey: String
|
||||||
|
|
||||||
enum LikeResult {
|
enum CountResult {
|
||||||
case user_already_liked
|
case already_counted
|
||||||
case success(Int)
|
case success(Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ class EventCounter {
|
|||||||
self.our_pubkey = our_pubkey
|
self.our_pubkey = our_pubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
func add_event(_ ev: NostrEvent, target: String) -> LikeResult {
|
func add_event(_ ev: NostrEvent, target: String) -> CountResult {
|
||||||
let pubkey = ev.pubkey
|
let pubkey = ev.pubkey
|
||||||
|
|
||||||
if self.user_events[pubkey] == nil {
|
if self.user_events[pubkey] == nil {
|
||||||
@@ -32,7 +32,7 @@ class EventCounter {
|
|||||||
|
|
||||||
if user_events[pubkey]!.contains(target) {
|
if user_events[pubkey]!.contains(target) {
|
||||||
// don't double count
|
// don't double count
|
||||||
return .user_already_liked
|
return .already_counted
|
||||||
}
|
}
|
||||||
|
|
||||||
user_events[pubkey]!.insert(target)
|
user_events[pubkey]!.insert(target)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct Liked {
|
struct Counted {
|
||||||
let like: NostrEvent
|
let event: NostrEvent
|
||||||
let id: String
|
let id: String
|
||||||
let total: Int
|
let total: Int
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class ThreadModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func subscribe() {
|
func subscribe() {
|
||||||
var ref_events = NostrFilter.filter_kinds([1,5,7])
|
var ref_events = NostrFilter.filter_kinds([1,5,6,7])
|
||||||
var events_filter = NostrFilter.filter_kinds([1])
|
var events_filter = NostrFilter.filter_kinds([1])
|
||||||
//var likes_filter = NostrFilter.filter_kinds(7])
|
//var likes_filter = NostrFilter.filter_kinds(7])
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible {
|
|||||||
var id: String
|
var id: String
|
||||||
var sig: String
|
var sig: String
|
||||||
var tags: [[String]]
|
var tags: [[String]]
|
||||||
|
var boosted_by: String?
|
||||||
|
|
||||||
// cached field for pow calc
|
// cached field for pow calc
|
||||||
var pow: Int?
|
var pow: Int?
|
||||||
@@ -53,6 +54,10 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible {
|
|||||||
return parse_mentions(content: self.content, tags: self.tags)
|
return parse_mentions(content: self.content, tags: self.tags)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
lazy var inner_event: NostrEvent? = {
|
||||||
|
return event_from_json(dat: self.content)
|
||||||
|
}()
|
||||||
|
|
||||||
lazy var event_refs: [EventRef] = {
|
lazy var event_refs: [EventRef] = {
|
||||||
return interpret_event_refs(blocks: self.blocks, tags: self.tags)
|
return interpret_event_refs(blocks: self.blocks, tags: self.tags)
|
||||||
}()
|
}()
|
||||||
@@ -335,13 +340,26 @@ func get_referenced_ids(tags: [[String]], key: String) -> [ReferencedId] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func make_boost_event(pubkey: String, privkey: String, boosted: NostrEvent) -> NostrEvent {
|
||||||
|
var tags: [[String]] = boosted.tags.filter { tag in tag.count >= 2 && (tag[0] == "e" || tag[0] == "p") }
|
||||||
|
tags.append(["e", boosted.id])
|
||||||
|
tags.append(["p", boosted.pubkey])
|
||||||
|
|
||||||
func make_like_event(pubkey: String, liked: NostrEvent) -> NostrEvent? {
|
let ev = NostrEvent(content: event_to_json(ev: boosted), pubkey: pubkey, kind: 6, tags: tags)
|
||||||
|
ev.calculate_id()
|
||||||
|
ev.sign(privkey: privkey)
|
||||||
|
return ev
|
||||||
|
}
|
||||||
|
|
||||||
|
func make_like_event(pubkey: String, privkey: String, liked: NostrEvent) -> NostrEvent {
|
||||||
var tags: [[String]] = liked.tags.filter { tag in tag.count >= 2 && (tag[0] == "e" || tag[0] == "p") }
|
var tags: [[String]] = liked.tags.filter { tag in tag.count >= 2 && (tag[0] == "e" || tag[0] == "p") }
|
||||||
tags.append(["e", liked.id])
|
tags.append(["e", liked.id])
|
||||||
tags.append(["p", liked.pubkey])
|
tags.append(["p", liked.pubkey])
|
||||||
|
let ev = NostrEvent(content: "", pubkey: pubkey, kind: 7, tags: tags)
|
||||||
|
ev.calculate_id()
|
||||||
|
ev.sign(privkey: privkey)
|
||||||
|
|
||||||
return NostrEvent(content: "", pubkey: pubkey, kind: 7, tags: tags)
|
return ev
|
||||||
}
|
}
|
||||||
|
|
||||||
func gather_reply_ids(our_pubkey: String, from: NostrEvent) -> [ReferencedId] {
|
func gather_reply_ids(our_pubkey: String, from: NostrEvent) -> [ReferencedId] {
|
||||||
@@ -355,6 +373,10 @@ func gather_reply_ids(our_pubkey: String, from: NostrEvent) -> [ReferencedId] {
|
|||||||
return ids
|
return ids
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func event_from_json(dat: String) -> NostrEvent? {
|
||||||
|
return try? JSONDecoder().decode(NostrEvent.self, from: Data(dat.utf8))
|
||||||
|
}
|
||||||
|
|
||||||
func event_to_json(ev: NostrEvent) -> String {
|
func event_to_json(ev: NostrEvent) -> String {
|
||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
guard let res = try? encoder.encode(ev) else {
|
guard let res = try? encoder.encode(ev) else {
|
||||||
|
|||||||
@@ -99,7 +99,13 @@ extension Notification.Name {
|
|||||||
|
|
||||||
extension Notification.Name {
|
extension Notification.Name {
|
||||||
static var boost: Notification.Name {
|
static var boost: Notification.Name {
|
||||||
return Notification.Name("boost post")
|
return Notification.Name("boost")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Notification.Name {
|
||||||
|
static var boosted: Notification.Name {
|
||||||
|
return Notification.Name("boosted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,10 +113,11 @@ struct ChatView: View {
|
|||||||
NoteContentView(event: event, profiles: damus.profiles, content: event.content)
|
NoteContentView(event: event, profiles: damus.profiles, content: event.content)
|
||||||
|
|
||||||
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
||||||
|
let bar = make_actionbar_model(ev: event, like_counter: damus.likes, boost_counter: damus.boosts)
|
||||||
EventActionBar(event: event,
|
EventActionBar(event: event,
|
||||||
our_pubkey: damus.pubkey,
|
our_pubkey: damus.pubkey,
|
||||||
profiles: damus.profiles,
|
profiles: damus.profiles,
|
||||||
bar: make_actionbar_model(ev: event, counter: damus.likes)
|
bar: bar
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ struct EventActionBar: View {
|
|||||||
HStack(alignment: .bottom) {
|
HStack(alignment: .bottom) {
|
||||||
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundColor(Color.gray)
|
.foregroundColor(bar.liked ? Color.red : Color.gray)
|
||||||
|
|
||||||
EventActionButton(img: bar.liked ? "heart.fill" : "heart", col: bar.liked ? Color.red : nil) {
|
EventActionButton(img: bar.liked ? "heart.fill" : "heart", col: bar.liked ? Color.red : nil) {
|
||||||
if bar.liked {
|
if bar.liked {
|
||||||
@@ -54,23 +54,29 @@ struct EventActionBar: View {
|
|||||||
}
|
}
|
||||||
.padding([.trailing], 40)
|
.padding([.trailing], 40)
|
||||||
|
|
||||||
EventActionButton(img: "arrow.2.squarepath", col: bar.boosted ? Color.green : nil) {
|
HStack(alignment: .bottom) {
|
||||||
if bar.boosted {
|
Text("\(bar.boosts > 0 ? "\(bar.boosts)" : "")")
|
||||||
notify(.delete, bar.our_boost)
|
.font(.footnote)
|
||||||
} else {
|
.foregroundColor(bar.boosted ? Color.green : Color.gray)
|
||||||
notify(.boost, event)
|
|
||||||
|
EventActionButton(img: "arrow.2.squarepath", col: bar.boosted ? Color.green : nil) {
|
||||||
|
if bar.boosted {
|
||||||
|
notify(.delete, bar.our_boost)
|
||||||
|
} else {
|
||||||
|
notify(.boost, event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.onReceive(handle_notify(.liked)) { n in
|
.onReceive(handle_notify(.liked)) { n in
|
||||||
let liked = n.object as! Liked
|
let liked = n.object as! Counted
|
||||||
if liked.id != event.id {
|
if liked.id != event.id {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.bar.likes = liked.total
|
self.bar.likes = liked.total
|
||||||
if liked.like.pubkey == our_pubkey {
|
if liked.event.pubkey == our_pubkey {
|
||||||
self.bar.our_like = liked.like
|
self.bar.our_like = liked.event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,28 @@ struct EventView: View {
|
|||||||
@EnvironmentObject var action_bar: ActionBarModel
|
@EnvironmentObject var action_bar: ActionBarModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let profile = damus.profiles.lookup(id: event.pubkey)
|
return Group {
|
||||||
HStack {
|
if event.known_kind == .boost, let inner_ev = event.inner_event {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
HStack {
|
||||||
|
Label("", systemImage: "arrow.2.squarepath")
|
||||||
|
.foregroundColor(Color.gray)
|
||||||
|
ProfileName(pubkey: event.pubkey, profile: damus.profiles.lookup(id: event.pubkey))
|
||||||
|
.foregroundColor(Color.gray)
|
||||||
|
Text(" Boosted")
|
||||||
|
.foregroundColor(Color.gray)
|
||||||
|
}
|
||||||
|
TextEvent(inner_ev)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TextEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextEvent(_ event: NostrEvent) -> some View {
|
||||||
|
return HStack {
|
||||||
|
let profile = damus.profiles.lookup(id: event.pubkey)
|
||||||
VStack {
|
VStack {
|
||||||
let pv = ProfileView(damus: damus, profile: ProfileModel(pubkey: event.pubkey, damus: damus))
|
let pv = ProfileView(damus: damus, profile: ProfileModel(pubkey: event.pubkey, damus: damus))
|
||||||
|
|
||||||
@@ -79,7 +99,8 @@ struct EventView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if has_action_bar {
|
if has_action_bar {
|
||||||
EventActionBar(event: event, our_pubkey: damus.pubkey, profiles: damus.profiles, bar: make_actionbar_model(ev: event, counter: damus.likes))
|
let bar = make_actionbar_model(ev: event, like_counter: damus.likes, boost_counter: damus.boosts)
|
||||||
|
EventActionBar(event: event, our_pubkey: damus.pubkey, profiles: damus.profiles, bar: bar)
|
||||||
}
|
}
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
@@ -159,10 +180,11 @@ func reply_others_desc(n: Int, n_pubkeys: Int) -> String {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
func make_actionbar_model(ev: NostrEvent, counter: EventCounter) -> ActionBarModel {
|
func make_actionbar_model(ev: NostrEvent, like_counter: EventCounter, boost_counter: EventCounter) -> ActionBarModel {
|
||||||
let likes = counter.counts[ev.id]
|
let likes = like_counter.counts[ev.id]
|
||||||
let our_like = counter.our_events[ev.id]
|
let boosts = boost_counter.counts[ev.id]
|
||||||
let our_boost: NostrEvent? = nil
|
let our_like = like_counter.our_events[ev.id]
|
||||||
|
let our_boost = boost_counter.our_events[ev.id]
|
||||||
|
|
||||||
return ActionBarModel(likes: likes ?? 0, our_like: our_like, our_boost: our_boost)
|
return ActionBarModel(likes: likes ?? 0, boosts: boosts ?? 0, our_like: our_like, our_boost: our_boost)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user