[appstore] Report Content
This view provides a way to report content (nudity, illegal, spam) to relays. Clients can use this information to filter or warn if they choose to. This is needed for the appstore release Changelog-Added: Added a way to report content
This commit is contained in:
@@ -133,6 +133,7 @@
|
||||
4CC7AAF4297F18B400430951 /* ReplyDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF3297F18B400430951 /* ReplyDescription.swift */; };
|
||||
4CC7AAF6297F1A6A00430951 /* EventBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF5297F1A6A00430951 /* EventBody.swift */; };
|
||||
4CC7AAF8297F1CEE00430951 /* EventProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF7297F1CEE00430951 /* EventProfile.swift */; };
|
||||
4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF9297F64AC00430951 /* EventMenu.swift */; };
|
||||
4CD7641B28A1641400B6928F /* EndBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD7641A28A1641400B6928F /* EndBlock.swift */; };
|
||||
4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F8CC281352B30009DFBB /* Notifications.swift */; };
|
||||
4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F9DD2852768D00C00DD9 /* ConfigView.swift */; };
|
||||
@@ -154,6 +155,8 @@
|
||||
4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */; };
|
||||
4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */; };
|
||||
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; };
|
||||
4CF0ABD42980996B00D66079 /* Report.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABD32980996B00D66079 /* Report.swift */; };
|
||||
4CF0ABD629817F5B00D66079 /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABD529817F5B00D66079 /* ReportView.swift */; };
|
||||
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
|
||||
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439E013296790CF0020672B /* ProfileZoomView.swift */; };
|
||||
647D9A8D2968520300A295DE /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647D9A8C2968520300A295DE /* SideMenuView.swift */; };
|
||||
@@ -361,6 +364,7 @@
|
||||
4CC7AAF3297F18B400430951 /* ReplyDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyDescription.swift; sourceTree = "<group>"; };
|
||||
4CC7AAF5297F1A6A00430951 /* EventBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventBody.swift; sourceTree = "<group>"; };
|
||||
4CC7AAF7297F1CEE00430951 /* EventProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventProfile.swift; sourceTree = "<group>"; };
|
||||
4CC7AAF9297F64AC00430951 /* EventMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventMenu.swift; sourceTree = "<group>"; };
|
||||
4CD7641A28A1641400B6928F /* EndBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndBlock.swift; sourceTree = "<group>"; };
|
||||
4CE4F8CC281352B30009DFBB /* Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
|
||||
4CE4F9DD2852768D00C00DD9 /* ConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigView.swift; sourceTree = "<group>"; };
|
||||
@@ -385,6 +389,8 @@
|
||||
4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileName.swift; sourceTree = "<group>"; };
|
||||
4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowView.swift; sourceTree = "<group>"; };
|
||||
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventActionBar.swift; sourceTree = "<group>"; };
|
||||
4CF0ABD32980996B00D66079 /* Report.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Report.swift; sourceTree = "<group>"; };
|
||||
4CF0ABD529817F5B00D66079 /* ReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportView.swift; sourceTree = "<group>"; };
|
||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
|
||||
6439E013296790CF0020672B /* ProfileZoomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZoomView.swift; sourceTree = "<group>"; };
|
||||
647D9A8C2968520300A295DE /* SideMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = "<group>"; };
|
||||
@@ -527,6 +533,7 @@
|
||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */,
|
||||
4CB88392296F798300DC99E7 /* ReactionsModel.swift */,
|
||||
7C45AE70297353390031D7BC /* KFImageModel.swift */,
|
||||
4CF0ABD32980996B00D66079 /* Report.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@@ -584,6 +591,7 @@
|
||||
9609F057296E220800069BF3 /* BannerImageView.swift */,
|
||||
4CB8838E296F781C00DC99E7 /* ReactionsView.swift */,
|
||||
6439E013296790CF0020672B /* ProfileZoomView.swift */,
|
||||
4CF0ABD529817F5B00D66079 /* ReportView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@@ -655,6 +663,7 @@
|
||||
4CC7AAF5297F1A6A00430951 /* EventBody.swift */,
|
||||
4CC7AAEA297F0AEC00430951 /* BuilderEventView.swift */,
|
||||
4CC7AAF7297F1CEE00430951 /* EventProfile.swift */,
|
||||
4CC7AAF9297F64AC00430951 /* EventMenu.swift */,
|
||||
);
|
||||
path = Events;
|
||||
sourceTree = "<group>";
|
||||
@@ -1020,6 +1029,7 @@
|
||||
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */,
|
||||
4C8682872814DE470026224F /* ProfileView.swift in Sources */,
|
||||
4C5F9114283D694D0052CD1C /* FollowTarget.swift in Sources */,
|
||||
4CF0ABD629817F5B00D66079 /* ReportView.swift in Sources */,
|
||||
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */,
|
||||
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */,
|
||||
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */,
|
||||
@@ -1053,6 +1063,7 @@
|
||||
E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */,
|
||||
4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */,
|
||||
4C3A1D332960DB0500558C0F /* Markdown.swift in Sources */,
|
||||
4CF0ABD42980996B00D66079 /* Report.swift in Sources */,
|
||||
4C0A3F97280F8E02000448DE /* ThreadView.swift in Sources */,
|
||||
4C06670B28FDE64700038D2A /* damus.c in Sources */,
|
||||
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */,
|
||||
@@ -1061,6 +1072,7 @@
|
||||
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
|
||||
4C75EFB528049D790006080F /* Relay.swift in Sources */,
|
||||
4CEE2AF1280B216B00AB5EEF /* EventDetailView.swift in Sources */,
|
||||
4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */,
|
||||
4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */,
|
||||
4C3AC7A52836987600E1F516 /* MainTabView.swift in Sources */,
|
||||
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */,
|
||||
|
||||
@@ -26,10 +26,12 @@ struct TimestampedProfile {
|
||||
|
||||
enum Sheets: Identifiable {
|
||||
case post
|
||||
case report(ReportTarget)
|
||||
case reply(NostrEvent)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case .report: return "report"
|
||||
case .post: return "post"
|
||||
case .reply(let ev): return "reply-" + ev.id
|
||||
}
|
||||
@@ -229,6 +231,20 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func MaybeReportView(target: ReportTarget) -> some View {
|
||||
Group {
|
||||
if let ds = damus_state {
|
||||
if let sec = ds.keypair.privkey {
|
||||
ReportView(pool: ds.pool, target: target, privkey: sec)
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
if let damus = self.damus_state {
|
||||
@@ -279,6 +295,8 @@ struct ContentView: View {
|
||||
}
|
||||
.sheet(item: $active_sheet) { item in
|
||||
switch item {
|
||||
case .report(let target):
|
||||
MaybeReportView(target: target)
|
||||
case .post:
|
||||
PostView(replying_to: nil, references: [])
|
||||
case .reply(let event):
|
||||
@@ -326,6 +344,10 @@ struct ContentView: View {
|
||||
}
|
||||
.onReceive(handle_notify(.like)) { like in
|
||||
}
|
||||
.onReceive(handle_notify(.report)) { notif in
|
||||
let target = notif.object as! ReportTarget
|
||||
self.active_sheet = .report(target)
|
||||
}
|
||||
.onReceive(handle_notify(.broadcast_event)) { obj in
|
||||
let ev = obj.object as! NostrEvent
|
||||
self.damus_state?.pool.send(.event(ev))
|
||||
|
||||
59
damus/Models/Report.swift
Normal file
59
damus/Models/Report.swift
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Report.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ReportType: String {
|
||||
case explicit
|
||||
case illegal
|
||||
case spam
|
||||
case impersonation
|
||||
}
|
||||
|
||||
struct ReportNoteTarget {
|
||||
let pubkey: String
|
||||
let note_id: String
|
||||
}
|
||||
|
||||
enum ReportTarget {
|
||||
case user(String)
|
||||
case note(ReportNoteTarget)
|
||||
}
|
||||
|
||||
struct Report {
|
||||
let type: ReportType
|
||||
let target: ReportTarget
|
||||
let message: String
|
||||
}
|
||||
|
||||
func create_report_tags(target: ReportTarget, type: ReportType) -> [[String]] {
|
||||
var tags: [[String]]
|
||||
switch target {
|
||||
case .user(let pubkey):
|
||||
tags = [["p", pubkey]]
|
||||
case .note(let notet):
|
||||
tags = [["e", notet.note_id], ["p", notet.pubkey]]
|
||||
}
|
||||
|
||||
tags.append(["report", type.rawValue])
|
||||
return tags
|
||||
}
|
||||
|
||||
func create_report_event(privkey: String, report: Report) -> NostrEvent? {
|
||||
guard let pubkey = privkey_to_pubkey(privkey: privkey) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let kind = 1984
|
||||
let tags = create_report_tags(target: report.target, type: report.type)
|
||||
let ev = NostrEvent(content: report.message, pubkey: pubkey, kind: kind, tags: tags)
|
||||
|
||||
ev.id = calculate_event_id(ev: ev)
|
||||
ev.sig = sign_event(privkey: privkey, ev: ev)
|
||||
|
||||
return ev
|
||||
}
|
||||
@@ -11,150 +11,81 @@ extension Notification.Name {
|
||||
static var thread_focus: Notification.Name {
|
||||
return Notification.Name("thread focus")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var relays_changed: Notification.Name {
|
||||
return Notification.Name("relays_changed")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var select_event: Notification.Name {
|
||||
return Notification.Name("select_event")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var select_quote: Notification.Name {
|
||||
return Notification.Name("select quote")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var reply: Notification.Name {
|
||||
return Notification.Name("reply")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var profile_updated: Notification.Name {
|
||||
return Notification.Name("profile_updated")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var switched_timeline: Notification.Name {
|
||||
return Notification.Name("switched_timeline")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var liked: Notification.Name {
|
||||
return Notification.Name("liked")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var open_profile: Notification.Name {
|
||||
return Notification.Name("open_profile")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var scroll_to_top: Notification.Name {
|
||||
return Notification.Name("scroll_to_to")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var broadcast_event: Notification.Name {
|
||||
return Notification.Name("broadcast event")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var open_thread: Notification.Name {
|
||||
return Notification.Name("open thread")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var notice: Notification.Name {
|
||||
return Notification.Name("notice")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var like: Notification.Name {
|
||||
return Notification.Name("like note")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var delete: Notification.Name {
|
||||
return Notification.Name("delete note")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var post: Notification.Name {
|
||||
return Notification.Name("send post")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var boost: Notification.Name {
|
||||
return Notification.Name("boost")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var boosted: Notification.Name {
|
||||
return Notification.Name("boosted")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var follow: Notification.Name {
|
||||
return Notification.Name("follow")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var unfollow: Notification.Name {
|
||||
return Notification.Name("unfollow")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var login: Notification.Name {
|
||||
return Notification.Name("login")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var logout: Notification.Name {
|
||||
return Notification.Name("logout")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var followed: Notification.Name {
|
||||
return Notification.Name("followed")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var chatroom_meta: Notification.Name {
|
||||
return Notification.Name("chatroom_meta")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var unfollowed: Notification.Name {
|
||||
return Notification.Name("unfollowed")
|
||||
}
|
||||
static var report: Notification.Name {
|
||||
return Notification.Name("report")
|
||||
}
|
||||
}
|
||||
|
||||
func handle_notify(_ name: Notification.Name) -> NotificationCenter.Publisher {
|
||||
|
||||
@@ -100,6 +100,8 @@ struct EventView: View {
|
||||
|
||||
Text("\(format_relative_time(event.created_at))")
|
||||
.foregroundColor(.gray)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
EventBody(damus_state: damus, event: event, size: .normal)
|
||||
@@ -171,35 +173,7 @@ extension View {
|
||||
|
||||
func event_context_menu(_ event: NostrEvent, pubkey: String, privkey: String?) -> some View {
|
||||
return self.contextMenu {
|
||||
Button {
|
||||
UIPasteboard.general.string = event.get_content(privkey)
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy Text", comment: "Context menu option for copying the text from an note."), systemImage: "doc.on.doc")
|
||||
}
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = bech32_pubkey(pubkey) ?? pubkey
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy User ID", comment: "Context menu option for copying the ID of the user who created the note."), systemImage: "person")
|
||||
}
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = bech32_note_id(event.id) ?? event.id
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy Note ID", comment: "Context menu option for copying the ID of the note."), systemImage: "note.text")
|
||||
}
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = event_to_json(ev: event)
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy Note JSON", comment: "Context menu option for copying the JSON text from the note."), systemImage: "j.square.on.square")
|
||||
}
|
||||
|
||||
Button {
|
||||
NotificationCenter.default.post(name: .broadcast_event, object: event)
|
||||
} label: {
|
||||
Label(NSLocalizedString("Broadcast", comment: "Context menu option for broadcasting the user's note to all of the user's connected relay servers."), systemImage: "globe")
|
||||
}
|
||||
EventMenuContext(event: event, privkey: privkey, pubkey: pubkey)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ struct EmbeddedEventView: View {
|
||||
|
||||
EventBody(damus_state: damus_state, event: event, size: .small)
|
||||
}
|
||||
.event_context_menu(event, pubkey: pubkey, privkey: damus_state.keypair.privkey)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
93
damus/Views/Events/EventMenu.swift
Normal file
93
damus/Views/Events/EventMenu.swift
Normal file
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// EventMenu.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EventMenuContext: View {
|
||||
let event: NostrEvent
|
||||
let privkey: String?
|
||||
let pubkey: String
|
||||
|
||||
var body: some View {
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = event.get_content(privkey)
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy Text", comment: "Context menu option for copying the text from an note."), systemImage: "doc.on.doc")
|
||||
}
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = bech32_pubkey(pubkey) ?? pubkey
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy User Pubkey", comment: "Context menu option for copying the ID of the user who created the note."), systemImage: "person")
|
||||
}
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = bech32_note_id(event.id) ?? event.id
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy Note ID", comment: "Context menu option for copying the ID of the note."), systemImage: "note.text")
|
||||
}
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = event_to_json(ev: event)
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy Note JSON", comment: "Context menu option for copying the JSON text from the note."), systemImage: "square.on.square")
|
||||
}
|
||||
|
||||
Button {
|
||||
let target: ReportTarget = .note(ReportNoteTarget(pubkey: event.pubkey, note_id: event.id))
|
||||
notify(.report, target)
|
||||
} label: {
|
||||
Label(NSLocalizedString("Report", comment: "Context menu option for reporting content."), systemImage: "exclamationmark.bubble")
|
||||
}
|
||||
|
||||
Button {
|
||||
NotificationCenter.default.post(name: .broadcast_event, object: event)
|
||||
} label: {
|
||||
Label(NSLocalizedString("Broadcast", comment: "Context menu option for broadcasting the user's note to all of the user's connected relay servers."), systemImage: "globe")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
struct EventMenu: UIViewRepresentable {
|
||||
|
||||
typealias UIViewType = UIButton
|
||||
|
||||
let saveAction = UIAction(title: "") { action in }
|
||||
let saveMenu = UIMenu(title: "", children: [
|
||||
UIAction(title: "First Menu Item", image: UIImage(systemName: "nameOfSFSymbol")) { action in
|
||||
//code action for menu item
|
||||
},
|
||||
UIAction(title: "First Menu Item", image: UIImage(systemName: "nameOfSFSymbol")) { action in
|
||||
//code action for menu item
|
||||
},
|
||||
UIAction(title: "First Menu Item", image: UIImage(systemName: "nameOfSFSymbol")) { action in
|
||||
//code action for menu item
|
||||
},
|
||||
])
|
||||
|
||||
func makeUIView(context: Context) -> UIButton {
|
||||
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
|
||||
button.showsMenuAsPrimaryAction = true
|
||||
button.menu = saveMenu
|
||||
|
||||
return button
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIButton, context: Context) {
|
||||
uiView.setImage(UIImage(systemName: "plus"), for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
struct EventMenu_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
EventMenu(event: test_event, privkey: nil, pubkey: test_event.pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -49,6 +49,7 @@ struct SelectedEventView: View {
|
||||
.padding([.top], 4)
|
||||
}
|
||||
.padding([.leading], 2)
|
||||
.event_context_menu(event, pubkey: pubkey, privkey: damus.keypair.privkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
115
damus/Views/ReportView.swift
Normal file
115
damus/Views/ReportView.swift
Normal file
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// ReportView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ReportView: View {
|
||||
let pool: RelayPool
|
||||
let target: ReportTarget
|
||||
let privkey: String
|
||||
|
||||
@State var report_sent: Bool = false
|
||||
@State var report_id: String = ""
|
||||
|
||||
var body: some View {
|
||||
if report_sent {
|
||||
Success
|
||||
} else {
|
||||
MainForm
|
||||
}
|
||||
}
|
||||
|
||||
var Success: some View {
|
||||
VStack(alignment: .center, spacing: 20) {
|
||||
Text("Report sent!")
|
||||
.font(.headline)
|
||||
|
||||
Text("Relays have been notified and clients will be able to use this information to filter content. Thank you!")
|
||||
|
||||
Text("Report ID:")
|
||||
|
||||
Text(report_id)
|
||||
|
||||
Button("Copy Report ID") {
|
||||
UIPasteboard.general.string = report_id
|
||||
let g = UIImpactFeedbackGenerator(style: .medium)
|
||||
g.impactOccurred()
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
func do_send_report(type: ReportType) {
|
||||
guard let ev = send_report(privkey: privkey, pool: pool, target: target, type: .spam) else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let note_id = bech32_note_id(ev.id) else {
|
||||
return
|
||||
}
|
||||
|
||||
report_sent = true
|
||||
report_id = note_id
|
||||
}
|
||||
|
||||
var MainForm: some View {
|
||||
VStack {
|
||||
|
||||
Text("Report")
|
||||
.font(.headline)
|
||||
.padding()
|
||||
|
||||
Form {
|
||||
Section(content: {
|
||||
Button("It's spam") {
|
||||
do_send_report(type: .spam)
|
||||
}
|
||||
|
||||
Button("Nudity or explicit content") {
|
||||
do_send_report(type: .explicit)
|
||||
}
|
||||
|
||||
Button("Illegal content") {
|
||||
do_send_report(type: .illegal)
|
||||
}
|
||||
|
||||
if case .user = target {
|
||||
Button("They are impersonating someone") {
|
||||
do_send_report(type: .impersonation)
|
||||
}
|
||||
}
|
||||
}, header: {
|
||||
Text("What do you want to report?")
|
||||
}, footer: {
|
||||
Text("Your report will be sent to the relays you are connected to")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func send_report(privkey: String, pool: RelayPool, target: ReportTarget, type: ReportType) -> NostrEvent? {
|
||||
let report = Report(type: type, target: target, message: "")
|
||||
guard let ev = create_report_event(privkey: privkey, report: report) else {
|
||||
return nil
|
||||
}
|
||||
pool.send(.event(ev))
|
||||
return ev
|
||||
}
|
||||
|
||||
struct ReportView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let ds = test_damus_state()
|
||||
VStack {
|
||||
|
||||
ReportView(pool: ds.pool, target: ReportTarget.user(""), privkey: "")
|
||||
|
||||
ReportView(pool: ds.pool, target: ReportTarget.user(""), privkey: "", report_sent: true, report_id: "report_id")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user