Browse Source

better chat view

Signed-off-by: William Casarin <jb55@jb55.com>
profiles-everywhere
William Casarin 3 years ago
parent
commit
090385d3da
  1. 6
      damus/Notifications.swift
  2. 114
      damus/Views/ChatView.swift
  3. 9
      damus/Views/ChatroomView.swift
  4. 2
      damus/Views/EventActionBar.swift
  5. 2
      damus/Views/EventView.swift
  6. 16
      damus/Views/ProfilePicView.swift
  7. 17
      damus/Views/ReplyQuoteView.swift

6
damus/Notifications.swift

@ -19,6 +19,12 @@ extension Notification.Name {
} }
} }
extension Notification.Name {
static var select_quote: Notification.Name {
return Notification.Name("select quote")
}
}
extension Notification.Name { extension Notification.Name {
static var broadcast_event: Notification.Name { static var broadcast_event: Notification.Name {
return Notification.Name("broadcast event") return Notification.Name("broadcast event")

114
damus/Views/ChatView.swift

@ -19,6 +19,26 @@ struct ChatView: View {
return prev_ev == nil || prev_ev!.pubkey != event.pubkey 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 { var is_active: Bool {
guard let ev = thread.event else { guard let ev = thread.event else {
return false return false
@ -56,65 +76,79 @@ struct ChatView: View {
Text("\(reply_desc(profiles: profiles, event: event))") Text("\(reply_desc(profiles: profiles, event: event))")
.font(.footnote) .font(.footnote)
.foregroundColor(.gray) .foregroundColor(.gray)
.frame(maxWidth: .infinity, alignment: .leading) .frame(alignment: .leading)
} }
@Environment(\.colorScheme) var colorScheme
var body: some View { var body: some View {
let profile = profiles.lookup(id: event.pubkey) let profile = profiles.lookup(id: event.pubkey)
HStack { HStack {
VStack { //ZStack {
if is_active || just_started { //Rectangle()
ProfilePicView(picture: profile?.picture, size: 32, highlight: is_active ? .main : .none) //.foregroundColor(Color.gray)
} //.frame(width: 2)
/*
if just_started { VStack {
ProfilePicView(picture: profile?.picture, size: 32, highlight: thread.event.id == event.id ? .main : .none) if is_active || just_started {
} else { ProfilePicView(picture: profile?.picture, size: 32, highlight: is_active ? .main : .none)
Text("\(format_relative_time(event.created_at))") }
.font(.footnote) /*
.foregroundColor(.gray.opacity(0.5)) 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() Spacer()
} }
.frame(maxWidth: 32) .frame(maxWidth: 32)
//}
VStack { Group {
if just_started { VStack(alignment: .leading) {
HStack { if just_started {
HStack {
ProfileName(pubkey: event.pubkey, profile: profile) ProfileName(pubkey: event.pubkey, profile: profile)
Text("\(format_relative_time(event.created_at))") Text("\(format_relative_time(event.created_at))")
.foregroundColor(.gray) .foregroundColor(.gray)
Spacer() }
} }
}
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 { if let ref_id = thread.replies.lookup(event.id) {
EventActionBar(event: event) if !is_reply_to_prev() {
.environmentObject(profiles) 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) .padding([.leading], 2)
.background(Color.secondary.opacity(0.1))
.cornerRadius(8.0)
//.border(Color.red) //.border(Color.red)
} }
.contentShape(Rectangle()) .contentShape(Rectangle())
.id(event.id) .id(event.id)
.frame(minHeight: just_started ? PFP_SIZE : 0) .frame(minHeight: just_started ? PFP_SIZE : 0)
.padding([.bottom], next_ev == nil ? 4 : 0) //.padding([.bottom], next_ev == nil ? 2 : 0)
//.border(Color.green) //.border(Color.green)
} }

9
damus/Views/ChatroomView.swift

@ -14,7 +14,7 @@ struct ChatroomView: View {
var body: some View { var body: some View {
ScrollViewReader { scroller in ScrollViewReader { scroller in
ScrollView { ScrollView {
LazyVStack { LazyVStack(alignment: .leading) {
let count = thread.events.count let count = thread.events.count
ForEach(Array(zip(thread.events, thread.events.indices)), id: \.0.id) { (ev, ind) in ForEach(Array(zip(thread.events, thread.events.indices)), id: \.0.id) { (ev, ind) in
ChatView(event: thread.events[ind], 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() { .onAppear() {
scroll_to_event(scroller: scroller, id: thread.event!.id, delay: 0.3, animate: true, anchor: .bottom) scroll_to_event(scroller: scroller, id: thread.event!.id, delay: 0.3, animate: true, anchor: .bottom)
} }

2
damus/Views/EventActionBar.swift

@ -25,8 +25,6 @@ struct EventActionBar: View {
var body: some View { var body: some View {
HStack { HStack {
Spacer()
/* /*
EventActionButton(img: "square.and.arrow.up") { EventActionButton(img: "square.and.arrow.up") {
print("share") print("share")

2
damus/Views/EventView.swift

@ -39,7 +39,7 @@ struct EventView: View {
let profile = profiles.lookup(id: event.pubkey) let profile = profiles.lookup(id: event.pubkey)
HStack { HStack {
VStack { VStack {
ProfilePicView(picture: profile?.picture, size: 64, highlight: highlight) ProfilePicView(picture: profile?.picture, size: PFP_SIZE!, highlight: highlight)
Spacer() Spacer()
} }

16
damus/Views/ProfilePicView.swift

@ -7,7 +7,7 @@
import SwiftUI import SwiftUI
let PFP_SIZE: CGFloat? = 64 let PFP_SIZE: CGFloat? = 52.0
let CORNER_RADIUS: CGFloat = 32 let CORNER_RADIUS: CGFloat = 32
func id_to_color(_ id: String) -> Color { func id_to_color(_ id: String) -> Color {
@ -27,7 +27,7 @@ func pfp_line_width(_ h: Highlight) -> CGFloat {
case .none: fallthrough case .none: fallthrough
case .reply: case .reply:
return 0 return 0
case .main: return 4 case .main: return 2
} }
} }
@ -35,20 +35,22 @@ struct ProfilePicView: View {
let picture: String? let picture: String?
let size: CGFloat let size: CGFloat
let highlight: Highlight let highlight: Highlight
var Placeholder: some View {
Color.purple.opacity(0.2)
}
var body: some View { var body: some View {
if let pic = picture.flatMap({ URL(string: $0) }) { if let pic = picture.flatMap({ URL(string: $0) }) {
AsyncImage(url: pic) { img in AsyncImage(url: pic) { img in
img.resizable() img.resizable()
} placeholder: { } placeholder: { Placeholder }
Color.purple.opacity(0.2)
}
.frame(width: size, height: size) .frame(width: size, height: size)
.clipShape(Circle()) .clipShape(Circle())
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight))) .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
.padding(2) .padding(2)
} else { } else {
Color.purple.opacity(0.2) Placeholder
.frame(width: size, height: size) .frame(width: size, height: size)
.cornerRadius(CORNER_RADIUS) .cornerRadius(CORNER_RADIUS)
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight))) .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))

17
damus/Views/ReplyQuoteView.swift

@ -16,19 +16,20 @@ struct ReplyQuoteView: View {
func MainContent(event: NostrEvent) -> some View { func MainContent(event: NostrEvent) -> some View {
HStack(alignment: .top) { HStack(alignment: .top) {
ProfilePicView(picture: profiles.lookup(id: event.pubkey)?.picture, size: 16, highlight: .none) Rectangle().frame(width: 2)
//.border(Color.blue) .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)) ProfileName(pubkey: event.pubkey, profile: profiles.lookup(id: event.pubkey))
Text("\(format_relative_time(event.created_at))") Text("\(format_relative_time(event.created_at))")
.foregroundColor(.gray) .foregroundColor(.gray)
Spacer()
} }
Text(event.content) Text(event.content)
.frame(maxWidth: .infinity, alignment: .leading) //.frame(maxWidth: .infinity, alignment: .leading)
.textSelection(.enabled) .textSelection(.enabled)
//Spacer() //Spacer()
@ -44,11 +45,9 @@ struct ReplyQuoteView: View {
MainContent(event: event) MainContent(event: event)
.padding(4) .padding(4)
.frame(maxHeight: 100) .frame(maxHeight: 100)
.background(event.id == thread.event!.id ? Color.red.opacity(0.2) : Color.secondary.opacity(0.2))
.cornerRadius(8.0)
.contentShape(Rectangle()) .contentShape(Rectangle())
.onTapGesture { .onTapGesture {
thread.set_active_event(event) NotificationCenter.default.post(name: .select_quote, object: event)
} }
} else { } else {
ProgressView() ProgressView()

Loading…
Cancel
Save