Mute events in threads
Changlog-Added: Mute events in threads
This commit is contained in:
@@ -166,6 +166,7 @@
|
|||||||
4CF0ABE12981A83900D66079 /* MutelistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE02981A83900D66079 /* MutelistView.swift */; };
|
4CF0ABE12981A83900D66079 /* MutelistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE02981A83900D66079 /* MutelistView.swift */; };
|
||||||
4CF0ABE32981BC7D00D66079 /* UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE22981BC7D00D66079 /* UserView.swift */; };
|
4CF0ABE32981BC7D00D66079 /* UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE22981BC7D00D66079 /* UserView.swift */; };
|
||||||
4CF0ABE52981EE0C00D66079 /* EULAView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE42981EE0C00D66079 /* EULAView.swift */; };
|
4CF0ABE52981EE0C00D66079 /* EULAView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE42981EE0C00D66079 /* EULAView.swift */; };
|
||||||
|
4CF0ABE7298444FD00D66079 /* MutedEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE6298444FC00D66079 /* MutedEventView.swift */; };
|
||||||
4CF0ABE929844AF100D66079 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE829844AF100D66079 /* AnyCodable.swift */; };
|
4CF0ABE929844AF100D66079 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABE829844AF100D66079 /* AnyCodable.swift */; };
|
||||||
4CF0ABEC29844B4700D66079 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABEB29844B4700D66079 /* AnyDecodable.swift */; };
|
4CF0ABEC29844B4700D66079 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABEB29844B4700D66079 /* AnyDecodable.swift */; };
|
||||||
4CF0ABEE29844B5500D66079 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABED29844B5500D66079 /* AnyEncodable.swift */; };
|
4CF0ABEE29844B5500D66079 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABED29844B5500D66079 /* AnyEncodable.swift */; };
|
||||||
@@ -422,6 +423,7 @@
|
|||||||
4CF0ABE02981A83900D66079 /* MutelistView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutelistView.swift; sourceTree = "<group>"; };
|
4CF0ABE02981A83900D66079 /* MutelistView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutelistView.swift; sourceTree = "<group>"; };
|
||||||
4CF0ABE22981BC7D00D66079 /* UserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserView.swift; sourceTree = "<group>"; };
|
4CF0ABE22981BC7D00D66079 /* UserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserView.swift; sourceTree = "<group>"; };
|
||||||
4CF0ABE42981EE0C00D66079 /* EULAView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EULAView.swift; sourceTree = "<group>"; };
|
4CF0ABE42981EE0C00D66079 /* EULAView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EULAView.swift; sourceTree = "<group>"; };
|
||||||
|
4CF0ABE6298444FC00D66079 /* MutedEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutedEventView.swift; sourceTree = "<group>"; };
|
||||||
4CF0ABE829844AF100D66079 /* AnyCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = "<group>"; };
|
4CF0ABE829844AF100D66079 /* AnyCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = "<group>"; };
|
||||||
4CF0ABEB29844B4700D66079 /* AnyDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = "<group>"; };
|
4CF0ABEB29844B4700D66079 /* AnyDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = "<group>"; };
|
||||||
4CF0ABED29844B5500D66079 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; };
|
4CF0ABED29844B5500D66079 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; };
|
||||||
@@ -715,6 +717,7 @@
|
|||||||
4CC7AAEA297F0AEC00430951 /* BuilderEventView.swift */,
|
4CC7AAEA297F0AEC00430951 /* BuilderEventView.swift */,
|
||||||
4CC7AAF7297F1CEE00430951 /* EventProfile.swift */,
|
4CC7AAF7297F1CEE00430951 /* EventProfile.swift */,
|
||||||
4CC7AAF9297F64AC00430951 /* EventMenu.swift */,
|
4CC7AAF9297F64AC00430951 /* EventMenu.swift */,
|
||||||
|
4CF0ABE6298444FC00D66079 /* MutedEventView.swift */,
|
||||||
);
|
);
|
||||||
path = Events;
|
path = Events;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1061,6 +1064,7 @@
|
|||||||
4C3EA66828FF5F9900C48A62 /* hex.c in Sources */,
|
4C3EA66828FF5F9900C48A62 /* hex.c in Sources */,
|
||||||
E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */,
|
E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */,
|
||||||
4C3BEFDC281DCE6100B3DE84 /* Liked.swift in Sources */,
|
4C3BEFDC281DCE6100B3DE84 /* Liked.swift in Sources */,
|
||||||
|
4CF0ABE7298444FD00D66079 /* MutedEventView.swift in Sources */,
|
||||||
4CF0ABE12981A83900D66079 /* MutelistView.swift in Sources */,
|
4CF0ABE12981A83900D66079 /* MutelistView.swift in Sources */,
|
||||||
4C75EFB128049D510006080F /* NostrResponse.swift in Sources */,
|
4C75EFB128049D510006080F /* NostrResponse.swift in Sources */,
|
||||||
4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */,
|
4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */,
|
||||||
|
|||||||
@@ -410,15 +410,8 @@ class HomeModel: ObservableObject {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func should_hide_event(_ ev: NostrEvent) -> Bool {
|
|
||||||
if damus_state.contacts.is_muted(ev.pubkey) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return !ev.should_show_event
|
|
||||||
}
|
|
||||||
|
|
||||||
func handle_text_event(sub_id: String, _ ev: NostrEvent) {
|
func handle_text_event(sub_id: String, _ ev: NostrEvent) {
|
||||||
if should_hide_event(ev) {
|
if should_hide_event(contacts: damus_state.contacts, ev: ev) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -726,3 +719,11 @@ func event_has_our_pubkey(_ ev: NostrEvent, our_pubkey: String) -> Bool {
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func should_hide_event(contacts: Contacts, ev: NostrEvent) -> Bool {
|
||||||
|
if contacts.is_muted(ev.pubkey) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return !ev.should_show_event
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ struct EventDetailView: View {
|
|||||||
}
|
}
|
||||||
toggle_thread_view()
|
toggle_thread_view()
|
||||||
}
|
}
|
||||||
case .event(let ev, let highlight):
|
case .event(let ev, let _):
|
||||||
EventView(event: ev, has_action_bar: true, damus: damus)
|
EventView(damus: damus, event: ev, has_action_bar: true)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if thread.initial_event.id == ev.id {
|
if thread.initial_event.id == ev.id {
|
||||||
toggle_thread_view()
|
toggle_thread_view()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ struct EventView: View {
|
|||||||
|
|
||||||
@EnvironmentObject var action_bar: ActionBarModel
|
@EnvironmentObject var action_bar: ActionBarModel
|
||||||
|
|
||||||
init(event: NostrEvent, has_action_bar: Bool, damus: DamusState) {
|
init(damus: DamusState, event: NostrEvent, has_action_bar: Bool) {
|
||||||
self.event = event
|
self.event = event
|
||||||
self.has_action_bar = has_action_bar
|
self.has_action_bar = has_action_bar
|
||||||
self.damus = damus
|
self.damus = damus
|
||||||
@@ -222,9 +222,9 @@ struct EventView_Previews: PreviewProvider {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
EventView(
|
EventView(
|
||||||
|
damus: test_damus_state(),
|
||||||
event: test_event,
|
event: test_event,
|
||||||
has_action_bar: true,
|
has_action_bar: true
|
||||||
damus: test_damus_state()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
|||||||
112
damus/Views/Events/MutedEventView.swift
Normal file
112
damus/Views/Events/MutedEventView.swift
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
//
|
||||||
|
// MutedEventView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2023-01-27.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MutedEventView: View {
|
||||||
|
let damus_state: DamusState
|
||||||
|
let event: NostrEvent
|
||||||
|
let scroller: ScrollViewProxy?
|
||||||
|
|
||||||
|
let selected: Bool
|
||||||
|
@Binding var nav_target: String?
|
||||||
|
@Binding var navigating: Bool
|
||||||
|
@State var shown: Bool
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
init(damus_state: DamusState, event: NostrEvent, scroller: ScrollViewProxy?, nav_target: Binding<String?>, navigating: Binding<Bool>, selected: Bool) {
|
||||||
|
self.damus_state = damus_state
|
||||||
|
self.event = event
|
||||||
|
self.scroller = scroller
|
||||||
|
self.selected = selected
|
||||||
|
self._nav_target = nav_target
|
||||||
|
self._navigating = navigating
|
||||||
|
self._shown = State(initialValue: !should_hide_event(contacts: damus_state.contacts, ev: event))
|
||||||
|
}
|
||||||
|
|
||||||
|
var should_mute: Bool {
|
||||||
|
return should_hide_event(contacts: damus_state.contacts, ev: event)
|
||||||
|
}
|
||||||
|
|
||||||
|
var FillColor: Color {
|
||||||
|
colorScheme == .light ? Color("DamusLightGrey") : Color("DamusDarkGrey")
|
||||||
|
}
|
||||||
|
|
||||||
|
var MutedBox: some View {
|
||||||
|
ZStack {
|
||||||
|
RoundedRectangle(cornerRadius: 20)
|
||||||
|
.foregroundColor(FillColor)
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Text("Post from a user you've blocked")
|
||||||
|
Spacer()
|
||||||
|
Button(shown ? "Hide" : "Show") {
|
||||||
|
shown.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var Event: some View {
|
||||||
|
Group {
|
||||||
|
if selected {
|
||||||
|
SelectedEventView(damus: damus_state, event: event)
|
||||||
|
} else {
|
||||||
|
EventView(damus: damus_state, event: event, has_action_bar: true)
|
||||||
|
.onTapGesture {
|
||||||
|
nav_target = event.id
|
||||||
|
navigating = true
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
// TODO: find another solution to prevent layout shifting and layout blocking on large responses
|
||||||
|
scroller?.scrollTo("main", anchor: .bottom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Group {
|
||||||
|
if should_mute {
|
||||||
|
MutedBox
|
||||||
|
}
|
||||||
|
if shown {
|
||||||
|
Event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onReceive(handle_notify(.new_mutes)) { notif in
|
||||||
|
guard let mutes = notif.object as? [String] else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if mutes.contains(event.pubkey) {
|
||||||
|
shown = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onReceive(handle_notify(.new_unmutes)) { notif in
|
||||||
|
guard let unmutes = notif.object as? [String] else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if unmutes.contains(event.pubkey) {
|
||||||
|
shown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MutedEventView_Previews: PreviewProvider {
|
||||||
|
@State static var nav_target: String? = nil
|
||||||
|
@State static var navigating: Bool = false
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
|
||||||
|
MutedEventView(damus_state: test_damus_state(), event: test_event, scroller: nil, nav_target: $nav_target, navigating: $navigating, selected: false)
|
||||||
|
.frame(width: .infinity, height: 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ struct ReplyView: View {
|
|||||||
ParticipantsView(damus_state: damus, references: $references, originalReferences: $originalReferences)
|
ParticipantsView(damus_state: damus, references: $references, originalReferences: $originalReferences)
|
||||||
}
|
}
|
||||||
ScrollView {
|
ScrollView {
|
||||||
EventView(event: replying_to, has_action_bar: false, damus: damus)
|
EventView(damus: damus, event: replying_to, has_action_bar: false)
|
||||||
}
|
}
|
||||||
PostView(replying_to: replying_to, references: references)
|
PostView(replying_to: replying_to, references: references)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,15 +255,13 @@ struct ThreadV2View: View {
|
|||||||
// MARK: - Parents events view
|
// MARK: - Parents events view
|
||||||
VStack {
|
VStack {
|
||||||
ForEach(thread.parentEvents, id: \.id) { event in
|
ForEach(thread.parentEvents, id: \.id) { event in
|
||||||
EventView(event: event, has_action_bar: true, damus: damus)
|
MutedEventView(damus_state: damus,
|
||||||
.onTapGesture {
|
event: event,
|
||||||
nav_target = event.id
|
scroller: reader,
|
||||||
navigating = true
|
nav_target: $nav_target,
|
||||||
}
|
navigating: $navigating,
|
||||||
.onAppear {
|
selected: false
|
||||||
// TODO: find another solution to prevent layout shifting and layout blocking on large responses
|
)
|
||||||
reader.scrollTo("main", anchor: .bottom)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.background(GeometryReader { geometry in
|
}.background(GeometryReader { geometry in
|
||||||
// get the height and width of the EventView view
|
// get the height and width of the EventView view
|
||||||
@@ -278,22 +276,25 @@ struct ThreadV2View: View {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// MARK: - Actual event view
|
// MARK: - Actual event view
|
||||||
SelectedEventView(
|
MutedEventView(
|
||||||
damus: damus,
|
damus_state: damus,
|
||||||
event: thread.current
|
event: thread.current,
|
||||||
|
scroller: reader,
|
||||||
|
nav_target: $nav_target,
|
||||||
|
navigating: $navigating,
|
||||||
|
selected: true
|
||||||
).id("main")
|
).id("main")
|
||||||
|
|
||||||
// MARK: - Responses of the actual event view
|
// MARK: - Responses of the actual event view
|
||||||
ForEach(thread.childEvents, id: \.id) { event in
|
ForEach(thread.childEvents, id: \.id) { event in
|
||||||
EventView(
|
MutedEventView(
|
||||||
|
damus_state: damus,
|
||||||
event: event,
|
event: event,
|
||||||
has_action_bar: true,
|
scroller: reader,
|
||||||
damus: damus
|
nav_target: $nav_target,
|
||||||
|
navigating: $navigating,
|
||||||
|
selected: false
|
||||||
)
|
)
|
||||||
.onTapGesture {
|
|
||||||
nav_target = event.id
|
|
||||||
navigating = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.padding()
|
}.padding()
|
||||||
}.navigationBarTitle(NSLocalizedString("Thread", comment: "Navigation bar title for note thread."))
|
}.navigationBarTitle(NSLocalizedString("Thread", comment: "Navigation bar title for note thread."))
|
||||||
|
|||||||
@@ -39,11 +39,7 @@ struct InnerTimelineView: View {
|
|||||||
EmptyTimelineView()
|
EmptyTimelineView()
|
||||||
} else {
|
} else {
|
||||||
ForEach(events.filter(filter), id: \.id) { (ev: NostrEvent) in
|
ForEach(events.filter(filter), id: \.id) { (ev: NostrEvent) in
|
||||||
//let tm = ThreadModel(event: inner_event_or_self(ev: ev), damus_state: damus)
|
EventView(damus: damus, event: ev, has_action_bar: true)
|
||||||
//let is_chatroom = should_show_chatroom(ev)
|
|
||||||
//let tv = ThreadView(thread: tm, damus: damus, is_chatroom: is_chatroom)
|
|
||||||
|
|
||||||
EventView(event: ev, has_action_bar: true, damus: damus)
|
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
nav_target = ev
|
nav_target = ev
|
||||||
navigating = true
|
navigating = true
|
||||||
|
|||||||
Reference in New Issue
Block a user