Fix various padding issues related to longform posts

1. Make a proper threaded EventShell variant
2. Fix padding everywhere

Changelog-Fixed: Fix padding on longform events
This commit is contained in:
William Casarin
2023-07-11 12:17:59 -07:00
parent d96ea593a5
commit 495859e07f
9 changed files with 175 additions and 165 deletions

View File

@@ -142,7 +142,10 @@ struct EventView_Previews: PreviewProvider {
EventView(damus: test_damus_state(), event: NostrEvent(content: "hello there https://jb55.com/s/Oct12-150217.png https://jb55.com/red-me.jb55 cool", pubkey: "pk"), show_friend_icon: true, size: .big)
*/
EventView( damus: test_damus_state(), event: test_event )
EventView( damus: test_damus_state(), event: test_longform_event.event, options: [.wide] )
}
.padding()
}
@@ -154,3 +157,4 @@ let test_event =
pubkey: "pk",
createdAt: Int64(Date().timeIntervalSince1970 - 100)
)

View File

@@ -25,20 +25,64 @@ struct EventShell<Content: View>: View {
}
func get_mention() -> Mention? {
if self.options.contains(.nested) {
if self.options.contains(.nested) || self.options.contains(.no_mentions) {
return nil
}
return first_eref_mention(ev: event, privkey: state.keypair.privkey)
}
func Mention(_ mention: Mention) -> some View {
return BuilderEventView(damus: state, event_id: mention.ref.id)
}
var body: some View {
var ActionBar: some View {
return EventActionBar(damus_state: state, event: event)
.padding([.top], 4)
}
func Pfp(is_anon: Bool) -> some View {
return MaybeAnonPfpView(state: state, is_anon: is_anon, pubkey: event.pubkey, size: options.contains(.small_pfp) ? eventview_pfp_size(.small) : PFP_SIZE )
}
var Threaded: some View {
HStack(alignment: .top) {
let is_anon = event_is_anonymous(ev: event)
VStack {
Pfp(is_anon: is_anon)
Spacer()
}
VStack(alignment: .leading) {
EventTop(state: state, event: event, is_anon: is_anon)
if !options.contains(.no_replying_to) {
ReplyPart(event: event, privkey: state.keypair.privkey, profiles: state.profiles)
}
content
if let mention = get_mention() {
Mention(mention)
}
if has_action_bar {
ActionBar
}
}
.padding([.leading], 2)
}
}
var Wide: some View {
VStack(alignment: .leading) {
let is_anon = event_is_anonymous(ev: event)
HStack(spacing: 10) {
MaybeAnonPfpView(state: state, is_anon: is_anon, pubkey: event.pubkey, size: options.contains(.small_pfp) ? eventview_pfp_size(.small) : PFP_SIZE )
Pfp(is_anon: is_anon)
VStack {
EventTop(state: state, event: event, is_anon: is_anon)
ReplyPart(event: event, privkey: state.keypair.privkey, profiles: state.profiles)
@@ -49,24 +93,44 @@ struct EventShell<Content: View>: View {
content
if !options.contains(.no_mentions), let mention = get_mention() {
BuilderEventView(damus: state, event_id: mention.ref.id)
Mention(mention)
.padding(.horizontal)
}
if has_action_bar {
//EmptyRect
EventActionBar(damus_state: state, event: event)
.padding([.leading, .trailing, .top])
ActionBar
.padding(.horizontal)
}
}
}
var body: some View {
Group {
if options.contains(.wide) {
Wide
} else {
Threaded
}
}
.contentShape(Rectangle())
.id(event.id)
.frame(maxWidth: .infinity, minHeight: PFP_SIZE)
.padding([.bottom], 2)
}
}
struct EventShell_Previews: PreviewProvider {
static var previews: some View {
EventShell(state: test_damus_state(), event: test_event, options: [.no_action_bar]) {
Text("Hello")
VStack {
EventShell(state: test_damus_state(), event: test_event, options: [.no_action_bar]) {
Text("Hello")
}
EventShell(state: test_damus_state(), event: test_event, options: [.no_action_bar, .wide]) {
Text("Hello")
}
}
.frame(height: 300)
}
}

View File

@@ -24,29 +24,42 @@ struct LongformPreview: View {
func Words(_ words: Int) -> Text {
Text(verbatim: words.description) + Text(verbatim: " ") + Text("Words")
}
var Main: some View {
VStack(alignment: .leading, spacing: 10) {
Text(event.title ?? "Untitled")
.font(.title)
Text(event.summary ?? "")
.foregroundColor(.gray)
if case .loaded(let arts) = artifacts.state,
case .parts(let parts) = arts
{
Words(parts.words).font(.footnote)
}
}
}
var body: some View {
EventShell(state: state, event: event.event, options: options.union(.no_mentions)) {
VStack(alignment: .leading, spacing: 10) {
Text(event.title ?? "Untitled")
.font(.title)
Text(event.summary ?? "")
.foregroundColor(.gray)
if case .loaded(let arts) = artifacts.state,
case .parts(let parts) = arts
{
Words(parts.words).font(.footnote)
}
if options.contains(.wide) {
Main.padding(.horizontal)
} else {
Main
}
.padding()
}
}
}
struct LongformPreview_Previews: PreviewProvider {
static var previews: some View {
LongformPreview(state: test_damus_state(), ev: test_longform_event.event, options: [])
VStack {
LongformPreview(state: test_damus_state(), ev: test_longform_event.event, options: [])
LongformPreview(state: test_damus_state(), ev: test_longform_event.event, options: [.wide])
}
.frame(height: 400)
}
}

View File

@@ -52,18 +52,16 @@ struct LongformView: View {
var body: some View {
EventShell(state: state, event: event.event, options: options) {
VStack {
SelectableText(attributedString: AttributedString(stringLiteral: event.title ?? "Untitled"), size: .title)
NoteContentView(damus_state: state, event: event.event, show_images: true, size: .selected, options: options)
}
SelectableText(attributedString: AttributedString(stringLiteral: event.title ?? "Untitled"), size: .title)
NoteContentView(damus_state: state, event: event.event, show_images: true, size: .selected, options: options)
}
}
}
let test_longform_event = LongformEvent.parse(from:
.init(content: "## Let me tell you why coffee is awesome\n**IT JUST IS**",
.init(id: "longform_id",
content: "## Let me tell you why coffee is awesome\n**IT JUST IS**",
pubkey: "pk",
kind: NostrKind.longform.rawValue,
tags: [

View File

@@ -47,8 +47,8 @@ struct SelectedEventView: View {
.padding(.horizontal)
}
EventBody(damus_state: damus, event: event, size: size, options: [.pad_content])
EventBody(damus_state: damus, event: event, size: size, options: [.wide])
if let mention = first_eref_mention(ev: event, privkey: damus.keypair.privkey) {
BuilderEventView(damus: damus, event_id: mention.ref.id)
.padding(.horizontal)
@@ -88,6 +88,5 @@ struct SelectedEventView: View {
struct SelectedEventView_Previews: PreviewProvider {
static var previews: some View {
SelectedEventView(damus: test_damus_state(), event: test_event, size: .selected)
.padding()
}
}

View File

@@ -14,13 +14,12 @@ struct EventViewOptions: OptionSet {
static let no_replying_to = EventViewOptions(rawValue: 1 << 1)
static let wide = EventViewOptions(rawValue: 1 << 3)
static let truncate_content = EventViewOptions(rawValue: 1 << 4)
static let pad_content = EventViewOptions(rawValue: 1 << 5)
static let no_translate = EventViewOptions(rawValue: 1 << 6)
static let small_pfp = EventViewOptions(rawValue: 1 << 7)
static let nested = EventViewOptions(rawValue: 1 << 8)
static let top_zap = EventViewOptions(rawValue: 1 << 9)
static let no_mentions = EventViewOptions(rawValue: 1 << 10)
static let no_translate = EventViewOptions(rawValue: 1 << 5)
static let small_pfp = EventViewOptions(rawValue: 1 << 6)
static let nested = EventViewOptions(rawValue: 1 << 7)
static let top_zap = EventViewOptions(rawValue: 1 << 8)
static let no_mentions = EventViewOptions(rawValue: 1 << 9)
static let embedded: EventViewOptions = [.no_action_bar, .small_pfp, .wide, .truncate_content, .nested]
}
@@ -39,51 +38,12 @@ struct TextEvent: View {
self.evdata = damus.events.get_cache_data(event.id)
}
var has_action_bar: Bool {
!options.contains(.no_action_bar)
}
var body: some View {
Group {
if options.contains(.wide) {
WideStyle
} else {
ThreadedStyle
}
}
.contentShape(Rectangle())
.id(event.id)
.frame(maxWidth: .infinity, minHeight: PFP_SIZE)
.padding([.bottom], 2)
}
func Pfp(is_anon: Bool) -> some View {
MaybeAnonPfpView(state: damus, is_anon: is_anon, pubkey: pubkey, size: options.contains(.small_pfp) ? eventview_pfp_size(.small) : PFP_SIZE )
}
func TopPart(is_anon: Bool) -> some View {
HStack(alignment: .center, spacing: 0) {
ProfileName(is_anon: is_anon)
TimeDot()
RelativeTime(time: self.evdata.relative_time)
Spacer()
EventMenuContext(damus: damus, event: event)
}
.lineLimit(1)
}
var WideStyle: some View {
EventShell(state: damus, event: event, options: options) {
EvBody(options: self.options.union(.pad_content))
EvBody(options: options)
}
}
func ProfileName(is_anon: Bool) -> some View {
let profile = damus.profiles.lookup(id: pubkey)
let pk = is_anon ? ANON_PUBKEY : pubkey
return EventProfileName(pubkey: pk, profile: profile, damus: damus, size: .normal)
}
func EvBody(options: EventViewOptions) -> some View {
let show_imgs = should_show_images(settings: damus.settings, contacts: damus.contacts, ev: event, our_pubkey: damus.pubkey)
return NoteContentView(
@@ -93,61 +53,8 @@ struct TextEvent: View {
size: .normal,
options: options
)
.fixedSize(horizontal: false, vertical: true)
}
func Mention(_ mention: Mention) -> some View {
return BuilderEventView(damus: damus, event_id: mention.ref.id)
}
var ActionBar: some View {
return EventActionBar(damus_state: damus, event: event)
.padding([.top], 4)
}
var EmptyRect: some View {
return Rectangle().frame(height: 2).opacity(0)
}
func get_mention() -> Mention? {
if self.options.contains(.nested) {
return nil
}
return first_eref_mention(ev: event, privkey: damus.keypair.privkey)
}
var ThreadedStyle: some View {
HStack(alignment: .top) {
let is_anon = event_is_anonymous(ev: event)
VStack {
Pfp(is_anon: is_anon)
Spacer()
}
VStack(alignment: .leading) {
TopPart(is_anon: is_anon)
if !options.contains(.no_replying_to) {
ReplyPart(event: event, privkey: damus.keypair.privkey, profiles: damus.profiles)
}
EvBody(options: self.options)
if let mention = get_mention() {
Mention(mention)
}
if has_action_bar {
EmptyRect
ActionBar
}
}
.padding([.leading], 2)
}
}
}
func event_has_tag(ev: NostrEvent, tag: String) -> Bool {

View File

@@ -54,7 +54,7 @@ struct NoteContentView: View {
}
var with_padding: Bool {
return options.contains(.pad_content)
return options.contains(.wide)
}
var preview: LinkViewRepresentable? {
@@ -185,16 +185,23 @@ struct NoteContentView: View {
func artifactPartsView(_ parts: [ArtifactPart]) -> some View {
LazyVStack {
LazyVStack(alignment: .leading) {
ForEach(parts.indices, id: \.self) { ind in
let part = parts[ind]
switch part {
case .text(let txt):
txt
.padding(.horizontal)
if with_padding {
txt.padding(.horizontal)
} else {
txt
}
case .invoice(let inv):
InvoiceView(our_pubkey: damus_state.pubkey, invoice: inv, settings: damus_state.settings)
.padding(.horizontal)
if with_padding {
InvoiceView(our_pubkey: damus_state.pubkey, invoice: inv, settings: damus_state.settings)
.padding(.horizontal)
} else {
InvoiceView(our_pubkey: damus_state.pubkey, invoice: inv, settings: damus_state.settings)
}
case .media(let media):
Text("media \(media.url.absoluteString)")
}
@@ -211,6 +218,7 @@ struct NoteContentView: View {
MainContent(artifacts: separated)
}
}
.fixedSize(horizontal: false, vertical: true)
}
var body: some View {
@@ -277,15 +285,6 @@ func mention_str(_ m: Mention, profiles: Profiles) -> CompatibleText {
}
}
struct NoteContentView_Previews: PreviewProvider {
static var previews: some View {
let state = test_damus_state()
let content = "hi there ¯\\_(ツ)_/¯ https://jb55.com/s/Oct12-150217.png 5739a762ef6124dd.jpg"
NoteContentView(damus_state: state, event: NostrEvent(content: content, pubkey: "pk"), show_images: true, size: .normal, options: [])
}
}
enum NoteArtifacts {
case separated(NoteArtifactsSeparated)
case parts(NoteArtifactsParts)
@@ -652,3 +651,18 @@ func trim_suffix(_ str: String) -> String {
func trim_prefix(_ str: String) -> String {
return str.replacingOccurrences(of: "^\\s+", with: "", options: .regularExpression)
}
struct NoteContentView_Previews: PreviewProvider {
static var previews: some View {
let state = test_damus_state()
VStack {
NoteContentView(damus_state: state, event: test_event, show_images: true, size: .normal, options: [])
NoteContentView(damus_state: state, event: test_longform_event.event, show_images: true, size: .normal, options: [.wide])
.border(Color.red)
}
}
}

View File

@@ -51,30 +51,41 @@ struct ReplyView: View {
Spacer()
}
}
func line(height: CGFloat) -> some View {
return Rectangle()
.fill(Color.gray.opacity(0.25))
.frame(width: 2, height: height)
.offset(x: 25, y: 40)
.padding(.leading)
}
var body: some View {
VStack(alignment: .leading) {
EventView(damus: damus, event: replying_to, options: [.no_action_bar])
.padding()
.background(GeometryReader { geometry in
let eventHeight = geometry.frame(in: .global).height
Rectangle()
.fill(Color.gray.opacity(0.25))
.frame(width: 2, height: eventHeight + 7)
.offset(x: 25, y: 40)
.padding(.leading)
line(height: eventHeight)
})
ReplyingToSection
.background(GeometryReader { geometry in
let replyingToHeight = geometry.frame(in: .global).height
Rectangle()
.fill(Color.gray.opacity(0.25))
.frame(width: 2, height: replyingToHeight)
.offset(x: 25, y: 40)
.padding(.leading)
line(height: replyingToHeight)
})
}
}
}
struct ReplyView_Previews: PreviewProvider {
static var previews: some View {
VStack {
ReplyView(replying_to: test_event, damus: test_damus_state(), originalReferences: .constant([]), references: .constant([]))
.frame(height: 300)
ReplyView(replying_to: test_longform_event.event, damus: test_damus_state(), originalReferences: .constant([]), references: .constant([]))
.frame(height: 300)
}
}
}

View File

@@ -24,7 +24,7 @@ struct RepostedEvent: View {
.buttonStyle(PlainButtonStyle())
//SelectedEventView(damus: damus, event: inner_ev, size: .normal)
EventView(damus: damus, event: inner_ev, pubkey: inner_ev.pubkey, options: options)
EventView(damus: damus, event: inner_ev, pubkey: inner_ev.pubkey, options: options.union(.wide))
}
}
}