@@ -19,6 +19,12 @@ extension Notification.Name {
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var select_quote: Notification.Name {
|
||||
return Notification.Name("select quote")
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static var broadcast_event: Notification.Name {
|
||||
return Notification.Name("broadcast event")
|
||||
|
||||
@@ -19,6 +19,26 @@ struct ChatView: View {
|
||||
return prev_ev == nil || prev_ev!.pubkey != event.pubkey
|
||||
}
|
||||
|
||||
func next_replies_to_this() -> Bool {
|
||||
guard let next = next_ev else {
|
||||
return false
|
||||
}
|
||||
|
||||
return thread.replies.lookup(next.id) != nil
|
||||
}
|
||||
|
||||
func is_reply_to_prev() -> Bool {
|
||||
guard let prev = prev_ev else {
|
||||
return true
|
||||
}
|
||||
|
||||
if let rep = thread.replies.lookup(event.id) {
|
||||
return rep == prev.id
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var is_active: Bool {
|
||||
guard let ev = thread.event else {
|
||||
return false
|
||||
@@ -56,65 +76,79 @@ struct ChatView: View {
|
||||
Text("\(reply_desc(profiles: profiles, event: event))")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.frame(alignment: .leading)
|
||||
}
|
||||
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
var body: some View {
|
||||
let profile = profiles.lookup(id: event.pubkey)
|
||||
HStack {
|
||||
VStack {
|
||||
if is_active || just_started {
|
||||
ProfilePicView(picture: profile?.picture, size: 32, highlight: is_active ? .main : .none)
|
||||
}
|
||||
/*
|
||||
if just_started {
|
||||
ProfilePicView(picture: profile?.picture, size: 32, highlight: thread.event.id == event.id ? .main : .none)
|
||||
} else {
|
||||
Text("\(format_relative_time(event.created_at))")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray.opacity(0.5))
|
||||
}
|
||||
*/
|
||||
//ZStack {
|
||||
//Rectangle()
|
||||
//.foregroundColor(Color.gray)
|
||||
//.frame(width: 2)
|
||||
|
||||
VStack {
|
||||
if is_active || just_started {
|
||||
ProfilePicView(picture: profile?.picture, size: 32, highlight: is_active ? .main : .none)
|
||||
}
|
||||
/*
|
||||
if just_started {
|
||||
ProfilePicView(picture: profile?.picture, size: 32, highlight: thread.event.id == event.id ? .main : .none)
|
||||
} else {
|
||||
Text("\(format_relative_time(event.created_at))")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray.opacity(0.5))
|
||||
}
|
||||
*/
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: 32)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: 32)
|
||||
//}
|
||||
|
||||
VStack {
|
||||
if just_started {
|
||||
HStack {
|
||||
Group {
|
||||
VStack(alignment: .leading) {
|
||||
if just_started {
|
||||
HStack {
|
||||
ProfileName(pubkey: event.pubkey, profile: profile)
|
||||
Text("\(format_relative_time(event.created_at))")
|
||||
.foregroundColor(.gray)
|
||||
Spacer()
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let ref_id = thread.replies.lookup(event.id) {
|
||||
ReplyQuoteView(quoter: event, event_id: ref_id)
|
||||
.environmentObject(thread)
|
||||
.environmentObject(profiles)
|
||||
ReplyDescription
|
||||
}
|
||||
|
||||
Text(event.content)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.textSelection(.enabled)
|
||||
|
||||
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
||||
EventActionBar(event: event)
|
||||
.environmentObject(profiles)
|
||||
}
|
||||
if let ref_id = thread.replies.lookup(event.id) {
|
||||
if !is_reply_to_prev() {
|
||||
ReplyQuoteView(quoter: event, event_id: ref_id)
|
||||
.environmentObject(thread)
|
||||
.environmentObject(profiles)
|
||||
ReplyDescription
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
Text(event.content)
|
||||
.textSelection(.enabled)
|
||||
|
||||
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
||||
EventActionBar(event: event)
|
||||
.environmentObject(profiles)
|
||||
}
|
||||
|
||||
//Spacer()
|
||||
}
|
||||
.padding(6)
|
||||
}
|
||||
.padding([.leading], 2)
|
||||
.background(Color.secondary.opacity(0.1))
|
||||
.cornerRadius(8.0)
|
||||
|
||||
//.border(Color.red)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.id(event.id)
|
||||
.frame(minHeight: just_started ? PFP_SIZE : 0)
|
||||
.padding([.bottom], next_ev == nil ? 4 : 0)
|
||||
//.padding([.bottom], next_ev == nil ? 2 : 0)
|
||||
//.border(Color.green)
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ struct ChatroomView: View {
|
||||
var body: some View {
|
||||
ScrollViewReader { scroller in
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
LazyVStack(alignment: .leading) {
|
||||
let count = thread.events.count
|
||||
ForEach(Array(zip(thread.events, thread.events.indices)), id: \.0.id) { (ev, ind) in
|
||||
ChatView(event: thread.events[ind],
|
||||
@@ -33,6 +33,13 @@ struct ChatroomView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .select_quote)) { notif in
|
||||
let ev = notif.object as! NostrEvent
|
||||
if ev.id != thread.event!.id {
|
||||
thread.set_active_event(ev)
|
||||
}
|
||||
scroll_to_event(scroller: scroller, id: ev.id, delay: 0, animate: true, anchor: .top)
|
||||
}
|
||||
.onAppear() {
|
||||
scroll_to_event(scroller: scroller, id: thread.event!.id, delay: 0.3, animate: true, anchor: .bottom)
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ struct EventActionBar: View {
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
/*
|
||||
EventActionButton(img: "square.and.arrow.up") {
|
||||
print("share")
|
||||
|
||||
@@ -39,7 +39,7 @@ struct EventView: View {
|
||||
let profile = profiles.lookup(id: event.pubkey)
|
||||
HStack {
|
||||
VStack {
|
||||
ProfilePicView(picture: profile?.picture, size: 64, highlight: highlight)
|
||||
ProfilePicView(picture: profile?.picture, size: PFP_SIZE!, highlight: highlight)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
let PFP_SIZE: CGFloat? = 64
|
||||
let PFP_SIZE: CGFloat? = 52.0
|
||||
let CORNER_RADIUS: CGFloat = 32
|
||||
|
||||
func id_to_color(_ id: String) -> Color {
|
||||
@@ -27,7 +27,7 @@ func pfp_line_width(_ h: Highlight) -> CGFloat {
|
||||
case .none: fallthrough
|
||||
case .reply:
|
||||
return 0
|
||||
case .main: return 4
|
||||
case .main: return 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,20 +35,22 @@ struct ProfilePicView: View {
|
||||
let picture: String?
|
||||
let size: CGFloat
|
||||
let highlight: Highlight
|
||||
|
||||
|
||||
var Placeholder: some View {
|
||||
Color.purple.opacity(0.2)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if let pic = picture.flatMap({ URL(string: $0) }) {
|
||||
AsyncImage(url: pic) { img in
|
||||
img.resizable()
|
||||
} placeholder: {
|
||||
Color.purple.opacity(0.2)
|
||||
}
|
||||
} placeholder: { Placeholder }
|
||||
.frame(width: size, height: size)
|
||||
.clipShape(Circle())
|
||||
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
|
||||
.padding(2)
|
||||
} else {
|
||||
Color.purple.opacity(0.2)
|
||||
Placeholder
|
||||
.frame(width: size, height: size)
|
||||
.cornerRadius(CORNER_RADIUS)
|
||||
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
|
||||
|
||||
@@ -16,19 +16,20 @@ struct ReplyQuoteView: View {
|
||||
|
||||
func MainContent(event: NostrEvent) -> some View {
|
||||
HStack(alignment: .top) {
|
||||
ProfilePicView(picture: profiles.lookup(id: event.pubkey)?.picture, size: 16, highlight: .none)
|
||||
//.border(Color.blue)
|
||||
Rectangle().frame(width: 2)
|
||||
.padding([.leading], 4)
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
HStack(alignment: .top) {
|
||||
ProfilePicView(picture: profiles.lookup(id: event.pubkey)?.picture, size: 16, highlight: .none)
|
||||
ProfileName(pubkey: event.pubkey, profile: profiles.lookup(id: event.pubkey))
|
||||
Text("\(format_relative_time(event.created_at))")
|
||||
.foregroundColor(.gray)
|
||||
Spacer()
|
||||
}
|
||||
|
||||
Text(event.content)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
//.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.textSelection(.enabled)
|
||||
|
||||
//Spacer()
|
||||
@@ -44,11 +45,9 @@ struct ReplyQuoteView: View {
|
||||
MainContent(event: event)
|
||||
.padding(4)
|
||||
.frame(maxHeight: 100)
|
||||
.background(event.id == thread.event!.id ? Color.red.opacity(0.2) : Color.secondary.opacity(0.2))
|
||||
.cornerRadius(8.0)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
thread.set_active_event(event)
|
||||
NotificationCenter.default.post(name: .select_quote, object: event)
|
||||
}
|
||||
} else {
|
||||
ProgressView()
|
||||
|
||||
Reference in New Issue
Block a user