commit c046c7cf457643706ef67b11cb37051003b05dc5
parent 5daaec35a8c0ba46dcdc53ddc0c809d7680df91a
Author: Terry Yiu <963907+tyiu@users.noreply.github.com>
Date: Sun, 22 Jan 2023 23:24:10 -0500
Add Reposts view
Changelog-Added: Reposts view
Closes: #376
Diffstat:
5 files changed, 163 insertions(+), 1 deletion(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -12,6 +12,9 @@
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAEC294FCCFC00EE4006 /* Constants.swift */; };
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; };
3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */; };
+ 3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; };
+ 3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; };
+ 3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.swift */; };
3ACB685C297633BC00C46468 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685A297633BC00C46468 /* InfoPlist.strings */; };
3ACB685F297633BC00C46468 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685D297633BC00C46468 /* Localizable.strings */; };
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
@@ -217,6 +220,9 @@
3A929C20297F2CF80090925E /* it-IT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "it-IT"; path = "it-IT.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
3A929C21297F2CF80090925E /* it-IT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "it-IT"; path = "it-IT.lproj/Localizable.strings"; sourceTree = "<group>"; };
3A929C22297F2CF80090925E /* it-IT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "it-IT"; path = "it-IT.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
+ 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepostsModel.swift; sourceTree = "<group>"; };
+ 3AA247FE297E3D900090C62D /* RepostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostsView.swift; sourceTree = "<group>"; };
+ 3AA24801297E3DC20090C62D /* RepostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostView.swift; sourceTree = "<group>"; };
3ACB685B297633BC00C46468 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
3ACB685E297633BC00C46468 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/Localizable.strings"; sourceTree = "<group>"; };
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeAgoTests.swift; sourceTree = "<group>"; };
@@ -466,6 +472,14 @@
path = "Empty Views";
sourceTree = "<group>";
};
+ 3AA24800297E3DAE0090C62D /* Reposts */ = {
+ isa = PBXGroup;
+ children = (
+ 3AA24801297E3DC20090C62D /* RepostView.swift */,
+ );
+ path = Reposts;
+ sourceTree = "<group>";
+ };
4C06670728FDE62900038D2A /* damus-c */ = {
isa = PBXGroup;
children = (
@@ -523,6 +537,7 @@
4C0A3F8D280F63FF000448DE /* Models */ = {
isa = PBXGroup;
children = (
+ 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */,
4C0A3F8E280F640A000448DE /* ThreadModel.swift */,
4C0A3F92280F66F5000448DE /* ReplyMap.swift */,
4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */,
@@ -565,6 +580,7 @@
children = (
4CF0ABDF2981A83000D66079 /* Muting */,
4CC7AAEE297F11B300430951 /* Events */,
+ 3AA24800297E3DAE0090C62D /* Reposts */,
4CB88394296F7F8100DC99E7 /* Reactions */,
4CB88387296AF97C00DC99E7 /* ActionBar */,
4CE4F9E228528C5200C00DD9 /* AddRelayView.swift */,
@@ -616,6 +632,7 @@
6439E013296790CF0020672B /* ProfileZoomView.swift */,
4CF0ABD529817F5B00D66079 /* ReportView.swift */,
4CF0ABE42981EE0C00D66079 /* EULAView.swift */,
+ 3AA247FE297E3D900090C62D /* RepostsView.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -992,6 +1009,7 @@
4CC7AAED297F0B9E00430951 /* Highlight.swift in Sources */,
4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */,
4C75EFB92804A2740006080F /* EventView.swift in Sources */,
+ 3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */,
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
4C633350283D40E500B1C9C3 /* HomeModel.swift in Sources */,
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */,
@@ -1060,6 +1078,7 @@
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
4C3EA64C28FF59AC00C48A62 /* bech32_util.c in Sources */,
4C363A9C282838B9006E126D /* EventRef.swift in Sources */,
+ 3AA24802297E3DC20090C62D /* RepostView.swift in Sources */,
4CD7641B28A1641400B6928F /* EndBlock.swift in Sources */,
4C3EA66528FF5F6800C48A62 /* mem.c in Sources */,
4CF0ABE52981EE0C00D66079 /* EULAView.swift in Sources */,
@@ -1110,6 +1129,7 @@
4C0A3F97280F8E02000448DE /* ThreadView.swift in Sources */,
4C06670B28FDE64700038D2A /* damus.c in Sources */,
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */,
+ 3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */,
4C99737B28C92A9200E53835 /* ChatroomMetadata.swift in Sources */,
4CC7AAF4297F18B400430951 /* ReplyDescription.swift in Sources */,
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
diff --git a/damus/Models/RepostsModel.swift b/damus/Models/RepostsModel.swift
@@ -0,0 +1,77 @@
+//
+// RepostsModel.swift
+// damus
+//
+// Created by Terry Yiu on 1/22/23.
+//
+
+import Foundation
+
+class RepostsModel: ObservableObject {
+ let state: DamusState
+ let target: String
+ let sub_id: String
+ let profiles_id: String
+
+ @Published var reposts: [NostrEvent]
+
+ init (state: DamusState, target: String) {
+ self.state = state
+ self.target = target
+ self.sub_id = UUID().description
+ self.profiles_id = UUID().description
+ self.reposts = []
+ }
+
+ func get_filter() -> NostrFilter {
+ var filter = NostrFilter.filter_kinds([NostrKind.boost.rawValue])
+ filter.referenced_ids = [target]
+ filter.limit = 500
+ return filter
+ }
+
+ func subscribe() {
+ let filter = get_filter()
+ let filters = [filter]
+ self.state.pool.subscribe(sub_id: sub_id, filters: filters, handler: handle_nostr_event)
+ }
+
+ func unsubscribe() {
+ self.state.pool.unsubscribe(sub_id: sub_id)
+ }
+
+ func handle_event(relay_id: String, ev: NostrEvent) {
+ guard ev.kind == NostrKind.boost.rawValue else {
+ return
+ }
+
+ guard let reposted_event = last_etag(tags: ev.tags) else {
+ return
+ }
+
+ guard reposted_event == self.target else {
+ return
+ }
+
+ if insert_uniq_sorted_event(events: &self.reposts, new_ev: ev, cmp: { a, b in a.created_at < b.created_at } ) {
+ objectWillChange.send()
+ }
+ }
+
+ func handle_nostr_event(relay_id: String, ev: NostrConnectionEvent) {
+ guard case .nostr_event(let nev) = ev else {
+ return
+ }
+
+ switch nev {
+ case .event(_, let ev):
+ handle_event(relay_id: relay_id, ev: ev)
+
+ case .notice(_):
+ break
+ case .eose(_):
+ load_profiles(profiles_subid: profiles_id, relay_id: relay_id, events: reposts, damus_state: state)
+ break
+ }
+ }
+}
diff --git a/damus/Views/ActionBar/EventDetailBar.swift b/damus/Views/ActionBar/EventDetailBar.swift
@@ -15,7 +15,10 @@ struct EventDetailBar: View {
var body: some View {
HStack {
if bar.boosts > 0 {
- Text("\(Text("\(bar.boosts)", comment: "Number of reposts.").font(.body.bold())) \(Text(String(format: NSLocalizedString("reposts_count", comment: "Part of a larger sentence to describe how many reposts there are."), bar.boosts)).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.")
+ NavigationLink(destination: RepostsView(damus_state: state, model: RepostsModel(state: state, target: target))) {
+ Text("\(Text("\(bar.boosts)", comment: "Number of reposts.").font(.body.bold())) \(Text(String(format: NSLocalizedString("reposts_count", comment: "Part of a larger sentence to describe how many reposts there are."), bar.boosts)).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.")
+ }
+ .buttonStyle(PlainButtonStyle())
}
if bar.likes > 0 {
diff --git a/damus/Views/Reposts/RepostView.swift b/damus/Views/Reposts/RepostView.swift
@@ -0,0 +1,24 @@
+//
+// RepostView.swift
+// damus
+//
+// Created by Terry Yiu on 1/22/23.
+//
+
+import SwiftUI
+
+struct RepostView: View {
+ let damus_state: DamusState
+ let repost: NostrEvent
+
+ var body: some View {
+ FollowUserView(target: .pubkey(repost.pubkey), damus_state: damus_state)
+ }
+}
+
+struct RepostView_Previews: PreviewProvider {
+ static var previews: some View {
+ RepostView(damus_state: test_damus_state(), repost: NostrEvent(id: "", content: "", pubkey: ""))
+ }
+}
+
diff --git a/damus/Views/RepostsView.swift b/damus/Views/RepostsView.swift
@@ -0,0 +1,38 @@
+//
+// RepostsView.swift
+// damus
+//
+// Created by Terry Yiu on 1/22/23.
+//
+
+import SwiftUI
+
+struct RepostsView: View {
+ let damus_state: DamusState
+ @StateObject var model: RepostsModel
+
+ var body: some View {
+ ScrollView {
+ LazyVStack {
+ ForEach(model.reposts, id: \.id) { ev in
+ RepostView(damus_state: damus_state, repost: ev)
+ }
+ }
+ .padding()
+ }
+ .navigationBarTitle(NSLocalizedString("Reposts", comment: "Navigation bar title for Reposts view."))
+ .onAppear {
+ model.subscribe()
+ }
+ .onDisappear {
+ model.unsubscribe()
+ }
+ }
+}
+
+struct RepostsView_Previews: PreviewProvider {
+ static var previews: some View {
+ let state = test_damus_state()
+ RepostsView(damus_state: state, model: RepostsModel(state: state, target: "pubkey"))
+ }
+}