mirror of
git://jb55.com/damus
synced 2024-09-18 19:23:49 +00:00
Inline image loading
Changelog-Added: Added inline image loading Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
parent
66eefa0ff2
commit
a47645929e
@ -9,6 +9,7 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
|
||||
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
|
||||
4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670528FCB08600038D2A /* ImageCarousel.swift */; };
|
||||
4C0A3F8C280F5FCA000448DE /* ChatroomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0A3F8B280F5FCA000448DE /* ChatroomView.swift */; };
|
||||
4C0A3F8F280F640A000448DE /* ThreadModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0A3F8E280F640A000448DE /* ThreadModel.swift */; };
|
||||
4C0A3F91280F6528000448DE /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0A3F90280F6528000448DE /* ChatView.swift */; };
|
||||
@ -128,6 +129,7 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
4C06670028FC7C5900038D2A /* RelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayView.swift; sourceTree = "<group>"; };
|
||||
4C06670528FCB08600038D2A /* ImageCarousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarousel.swift; sourceTree = "<group>"; };
|
||||
4C0A3F8B280F5FCA000448DE /* ChatroomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomView.swift; sourceTree = "<group>"; };
|
||||
4C0A3F8E280F640A000448DE /* ThreadModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadModel.swift; sourceTree = "<group>"; };
|
||||
4C0A3F90280F6528000448DE /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = "<group>"; };
|
||||
@ -378,6 +380,7 @@
|
||||
children = (
|
||||
4CE4F9E0285287B800C00DD9 /* TextFieldAlert.swift */,
|
||||
4CD7641A28A1641400B6928F /* EndBlock.swift */,
|
||||
4C06670528FCB08600038D2A /* ImageCarousel.swift */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
@ -654,6 +657,7 @@
|
||||
4C216F32286E388800040376 /* DMChatView.swift in Sources */,
|
||||
4C64987E286D082C00EAE2B3 /* DirectMessagesModel.swift in Sources */,
|
||||
4C363A8828236948006E126D /* BlocksView.swift in Sources */,
|
||||
4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */,
|
||||
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
|
||||
4C363A9C282838B9006E126D /* EventRef.swift in Sources */,
|
||||
4CD7641B28A1641400B6928F /* EndBlock.swift in Sources */,
|
||||
|
69
damus/Components/ImageCarousel.swift
Normal file
69
damus/Components/ImageCarousel.swift
Normal file
@ -0,0 +1,69 @@
|
||||
//
|
||||
// ImageCarousel.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2022-10-16.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Kingfisher
|
||||
|
||||
struct ImageViewer: View {
|
||||
let urls: [URL]
|
||||
|
||||
var body: some View {
|
||||
TabView {
|
||||
ForEach(urls, id: \.absoluteString) { url in
|
||||
VStack{
|
||||
Text(url.lastPathComponent)
|
||||
|
||||
KFImage(url)
|
||||
.loadDiskFileSynchronously()
|
||||
.scaleFactor(UIScreen.main.scale)
|
||||
.fade(duration: 0.1)
|
||||
.tabItem {
|
||||
Text(url.absoluteString)
|
||||
}
|
||||
.id(url.absoluteString)
|
||||
}
|
||||
}
|
||||
}
|
||||
.tabViewStyle(PageTabViewStyle())
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageCarousel: View {
|
||||
var urls: [URL]
|
||||
|
||||
@State var open_sheet: Bool = false
|
||||
@State var current_url: URL? = nil
|
||||
|
||||
var body: some View {
|
||||
TabView {
|
||||
ForEach(urls, id: \.absoluteString) { url in
|
||||
KFImage(url)
|
||||
.loadDiskFileSynchronously()
|
||||
.scaleFactor(UIScreen.main.scale)
|
||||
.fade(duration: 0.1)
|
||||
.tabItem {
|
||||
Text(url.absoluteString)
|
||||
}
|
||||
.id(url.absoluteString)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $open_sheet) {
|
||||
ImageViewer(urls: urls)
|
||||
}
|
||||
.frame(height: 200)
|
||||
.onTapGesture {
|
||||
open_sheet = true
|
||||
}
|
||||
.tabViewStyle(PageTabViewStyle())
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageCarousel_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ImageCarousel(urls: [URL(string: "https://jb55.com/red-me.jpg")!])
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
|
||||
import SwiftUI
|
||||
import Starscream
|
||||
//import Kingfisher
|
||||
import Kingfisher
|
||||
|
||||
let BOOTSTRAP_RELAYS = [
|
||||
"wss://relay.damus.io",
|
||||
|
@ -80,6 +80,8 @@ func build_mention_indices(_ blocks: [Block], type: MentionType) -> Set<Int> {
|
||||
return
|
||||
case .hashtag:
|
||||
return
|
||||
case .url:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ enum Block {
|
||||
case text(String)
|
||||
case mention(Mention)
|
||||
case hashtag(String)
|
||||
case url(URL)
|
||||
|
||||
var is_hashtag: String? {
|
||||
if case .hashtag(let htag) = self {
|
||||
@ -45,6 +46,14 @@ enum Block {
|
||||
return nil
|
||||
}
|
||||
|
||||
var is_url: URL? {
|
||||
if case .url(let url) = self {
|
||||
return url
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var is_text: String? {
|
||||
if case .text(let txt) = self {
|
||||
return txt
|
||||
@ -69,6 +78,8 @@ func render_blocks(blocks: [Block]) -> String {
|
||||
return str + txt
|
||||
case .hashtag(let htag):
|
||||
return str + "#" + htag
|
||||
case .url(let url):
|
||||
return str + url.absoluteString
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,21 +94,43 @@ func parse_mentions(content: String, tags: [[String]]) -> [Block] {
|
||||
var starting_from: Int = 0
|
||||
|
||||
while p.pos < content.count {
|
||||
if !consume_until(p, match: { $0 == "#" }) {
|
||||
if !consume_until(p, match: { !$0.isWhitespace}) {
|
||||
break
|
||||
}
|
||||
|
||||
let pre_mention = p.pos
|
||||
if let mention = parse_mention(p, tags: tags) {
|
||||
blocks.append(parse_textblock(str: p.str, from: starting_from, to: pre_mention))
|
||||
blocks.append(.mention(mention))
|
||||
starting_from = p.pos
|
||||
} else if let hashtag = parse_hashtag(p) {
|
||||
blocks.append(parse_textblock(str: p.str, from: starting_from, to: pre_mention))
|
||||
blocks.append(.hashtag(hashtag))
|
||||
starting_from = p.pos
|
||||
|
||||
let c = peek_char(p, 0)
|
||||
let pr = peek_char(p, -1)
|
||||
|
||||
if c == "#" {
|
||||
if let mention = parse_mention(p, tags: tags) {
|
||||
blocks.append(parse_textblock(str: p.str, from: starting_from, to: pre_mention))
|
||||
blocks.append(.mention(mention))
|
||||
starting_from = p.pos
|
||||
} else if let hashtag = parse_hashtag(p) {
|
||||
blocks.append(parse_textblock(str: p.str, from: starting_from, to: pre_mention))
|
||||
blocks.append(.hashtag(hashtag))
|
||||
starting_from = p.pos
|
||||
} else {
|
||||
if !consume_until(p, match: { $0.isWhitespace }) {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if c == "h" && (pr == nil || pr!.isWhitespace) {
|
||||
if let url = parse_url(p) {
|
||||
blocks.append(parse_textblock(str: p.str, from: starting_from, to: pre_mention))
|
||||
blocks.append(.url(url))
|
||||
starting_from = p.pos
|
||||
} else {
|
||||
if !consume_until(p, match: { $0.isWhitespace }) {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p.pos += 1
|
||||
if !consume_until(p, match: { $0.isWhitespace }) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,6 +178,37 @@ func is_punctuation(_ c: Character) -> Bool {
|
||||
return c.isWhitespace || c.isPunctuation
|
||||
}
|
||||
|
||||
func parse_url(_ p: Parser) -> URL? {
|
||||
let start = p.pos
|
||||
|
||||
if !parse_str(p, "http") {
|
||||
return nil
|
||||
}
|
||||
|
||||
if parse_char(p, "s") {
|
||||
if !parse_str(p, "://") {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if !parse_str(p, "://") {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if !consume_until(p, match: { c in c.isWhitespace }, end_ok: true) {
|
||||
p.pos = start
|
||||
return nil
|
||||
}
|
||||
|
||||
let url_str = String(substring(p.str, start: start, end: p.pos))
|
||||
guard let url = URL(string: url_str) else {
|
||||
p.pos = start
|
||||
return nil
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
func parse_hashtag(_ p: Parser) -> String? {
|
||||
let start = p.pos
|
||||
|
||||
|
@ -55,6 +55,15 @@ func parse_str(_ p: Parser, _ s: String) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func peek_char(_ p: Parser, _ i: Int) -> Character? {
|
||||
let offset = p.pos + i
|
||||
if offset < 0 || offset > p.str.count {
|
||||
return nil
|
||||
}
|
||||
let ind = p.str.index(p.str.startIndex, offsetBy: offset)
|
||||
return p.str[ind]
|
||||
}
|
||||
|
||||
func parse_char(_ p: Parser, _ c: Character) -> Bool {
|
||||
if p.pos >= p.str.count {
|
||||
return false
|
||||
|
@ -106,7 +106,7 @@ struct ChatView: View {
|
||||
}
|
||||
}
|
||||
|
||||
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, content: event.content)
|
||||
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, show_images: true, content: event.content)
|
||||
|
||||
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
||||
let bar = make_actionbar_model(ev: event, damus: damus_state)
|
||||
|
@ -21,7 +21,7 @@ struct DMView: View {
|
||||
Spacer()
|
||||
}
|
||||
|
||||
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, content: event.get_content(damus_state.keypair.privkey))
|
||||
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, show_images: true, content: event.get_content(damus_state.keypair.privkey))
|
||||
.foregroundColor(is_ours ? Color.white : Color.primary)
|
||||
.padding(10)
|
||||
.background(is_ours ? Color.accentColor : Color.secondary.opacity(0.15))
|
||||
|
@ -39,6 +39,20 @@ struct EventActionBar: View {
|
||||
notify(.reply, event)
|
||||
}
|
||||
}
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
Text("\(bar.boosts > 0 ? "\(bar.boosts)" : "")")
|
||||
.font(.footnote)
|
||||
.foregroundColor(bar.boosted ? Color.green : Color.gray)
|
||||
|
||||
EventActionButton(img: "arrow.2.squarepath", col: bar.boosted ? Color.green : nil) {
|
||||
if bar.boosted {
|
||||
notify(.delete, bar.our_boost)
|
||||
} else {
|
||||
self.confirm_boost = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
||||
@ -53,21 +67,8 @@ struct EventActionBar: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
Text("\(bar.boosts > 0 ? "\(bar.boosts)" : "")")
|
||||
.font(.footnote)
|
||||
.foregroundColor(bar.boosted ? Color.green : Color.gray)
|
||||
|
||||
EventActionButton(img: "arrow.2.squarepath", col: bar.boosted ? Color.green : nil) {
|
||||
if bar.boosted {
|
||||
notify(.delete, bar.our_boost)
|
||||
} else {
|
||||
self.confirm_boost = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
HStack(alignment: .bottom) {
|
||||
Text("\(bar.tips > 0 ? "\(bar.tips)" : "")")
|
||||
.font(.footnote)
|
||||
@ -81,6 +82,7 @@ struct EventActionBar: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
.padding(.top, 1)
|
||||
.alert("Boost", isPresented: $confirm_boost) {
|
||||
|
@ -127,13 +127,13 @@ func scroll_after_load(thread: ThreadModel, proxy: ScrollViewProxy) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
struct EventDetailView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
EventDetailView(event: NostrEvent(content: "Hello", pubkey: "Guy"), profile: nil)
|
||||
let state = test_damus_state()
|
||||
let tm = ThreadModel(evid: "4da698ceac09a16cdb439276fa3d13ef8f6620ffb45d11b76b3f103483c2d0b0", damus_state: state)
|
||||
EventDetailView(damus: state, thread: tm)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/// Find the entire reply path for the active event
|
||||
func make_reply_map(active: NostrEvent, events: [NostrEvent], privkey: String?) -> [String: ()]
|
||||
|
@ -129,9 +129,8 @@ struct EventView: View {
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
NoteContentView(privkey: damus.keypair.privkey, event: event, profiles: damus.profiles, content: content)
|
||||
NoteContentView(privkey: damus.keypair.privkey, event: event, profiles: damus.profiles, show_images: true, content: content)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.textSelection(.enabled)
|
||||
|
||||
if has_action_bar {
|
||||
let bar = make_actionbar_model(ev: event, damus: damus)
|
||||
@ -146,7 +145,7 @@ struct EventView: View {
|
||||
.contentShape(Rectangle())
|
||||
.background(event_validity_color(event.validity))
|
||||
.id(event.id)
|
||||
.frame(minHeight: PFP_SIZE)
|
||||
.frame(maxWidth: .infinity, minHeight: PFP_SIZE)
|
||||
.padding([.bottom], 4)
|
||||
.event_context_menu(event, privkey: damus.keypair.privkey)
|
||||
}
|
||||
@ -269,3 +268,8 @@ func make_actionbar_model(ev: NostrEvent, damus: DamusState) -> ActionBarModel {
|
||||
}
|
||||
|
||||
|
||||
struct EventView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,10 @@
|
||||
import SwiftUI
|
||||
|
||||
|
||||
func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -> String {
|
||||
func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -> (String, [URL]) {
|
||||
let blocks = ev.blocks(privkey)
|
||||
return blocks.reduce("") { str, block in
|
||||
var img_urls: [URL] = []
|
||||
let txt = blocks.reduce("") { str, block in
|
||||
switch block {
|
||||
case .mention(let m):
|
||||
return str + mention_str(m, profiles: profiles)
|
||||
@ -18,8 +19,20 @@ func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -
|
||||
return str + txt
|
||||
case .hashtag(let htag):
|
||||
return str + hashtag_str(htag)
|
||||
case .url(let url):
|
||||
if is_image_url(url) {
|
||||
img_urls.append(url)
|
||||
}
|
||||
return str + url.absoluteString
|
||||
}
|
||||
}
|
||||
|
||||
return (txt, img_urls)
|
||||
}
|
||||
|
||||
func is_image_url(_ url: URL) -> Bool {
|
||||
let str = url.lastPathComponent
|
||||
return str.hasSuffix("png") || str.hasSuffix("jpg") || str.hasSuffix("jpeg")
|
||||
}
|
||||
|
||||
struct NoteContentView: View {
|
||||
@ -27,23 +40,33 @@ struct NoteContentView: View {
|
||||
let event: NostrEvent
|
||||
let profiles: Profiles
|
||||
|
||||
let show_images: Bool
|
||||
|
||||
@State var content: String
|
||||
@State var images: [URL] = []
|
||||
|
||||
func MainContent() -> some View {
|
||||
let md_opts: AttributedString.MarkdownParsingOptions =
|
||||
.init(interpretedSyntax: .inlineOnlyPreservingWhitespace)
|
||||
|
||||
guard let txt = try? AttributedString(markdown: content, options: md_opts) else {
|
||||
return Text(content)
|
||||
return VStack(alignment: .leading) {
|
||||
if let txt = try? AttributedString(markdown: content, options: md_opts) {
|
||||
Text(txt)
|
||||
} else {
|
||||
Text(content)
|
||||
}
|
||||
if show_images && images.count > 0 {
|
||||
ImageCarousel(urls: images)
|
||||
}
|
||||
}
|
||||
|
||||
return Text(txt)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
MainContent()
|
||||
.onAppear() {
|
||||
self.content = render_note_content(ev: event, profiles: profiles, privkey: privkey)
|
||||
let (txt, images) = render_note_content(ev: event, profiles: profiles, privkey: privkey)
|
||||
self.content = txt
|
||||
self.images = images
|
||||
}
|
||||
.onReceive(handle_notify(.profile_updated)) { notif in
|
||||
let profile = notif.object as! ProfileUpdate
|
||||
@ -52,10 +75,13 @@ struct NoteContentView: View {
|
||||
switch block {
|
||||
case .mention(let m):
|
||||
if m.type == .pubkey && m.ref.ref_id == profile.pubkey {
|
||||
content = render_note_content(ev: event, profiles: profiles, privkey: privkey)
|
||||
let (txt, images) = render_note_content(ev: event, profiles: profiles, privkey: privkey)
|
||||
self.content = txt
|
||||
self.images = images
|
||||
}
|
||||
case .text: return
|
||||
case .hashtag: return
|
||||
case .url: return
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -80,10 +106,10 @@ func mention_str(_ m: Mention, profiles: Profiles) -> String {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
struct NoteContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NoteContentView()
|
||||
let state = test_damus_state()
|
||||
let content = "hi there https://jb55.com/s/Oct12-150217.png 5739a762ef6124dd.jpg"
|
||||
NoteContentView(privkey: "", event: NostrEvent(content: content, pubkey: "pk"), profiles: state.profiles, show_images: true, content: content)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -56,9 +56,8 @@ struct ProfilePicView: View {
|
||||
Group {
|
||||
let pic = picture ?? profiles.lookup(id: pubkey)?.picture ?? robohash(pubkey)
|
||||
let url = URL(string: pic)
|
||||
let processor = /*DownsamplingImageProcessor(size: CGSize(width: size, height: size))
|
||||
|>*/ ResizingImageProcessor(referenceSize: CGSize(width: size, height: size))
|
||||
|> RoundCornerImageProcessor(cornerRadius: 20)
|
||||
let processor = ResizingImageProcessor(referenceSize: CGSize(width: size, height: size))
|
||||
|
||||
KFImage.url(url)
|
||||
.placeholder { _ in
|
||||
Placeholder
|
||||
@ -67,6 +66,7 @@ struct ProfilePicView: View {
|
||||
.scaleFactor(UIScreen.main.scale)
|
||||
.loadDiskFileSynchronously()
|
||||
.fade(duration: 0.1)
|
||||
.clipShape(Circle())
|
||||
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ struct ReplyQuoteView: View {
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
|
||||
NoteContentView(privkey: privkey, event: event, profiles: profiles, content: event.content)
|
||||
NoteContentView(privkey: privkey, event: event, profiles: profiles, show_images: false, content: event.content)
|
||||
.font(.callout)
|
||||
.foregroundColor(.accentColor)
|
||||
|
||||
|
@ -31,8 +31,8 @@ class ReplyTests: XCTestCase {
|
||||
XCTAssertNil(ref.is_reply)
|
||||
XCTAssertNil(ref.is_thread_id)
|
||||
XCTAssertNil(ref.is_direct_reply)
|
||||
XCTAssertEqual(ref.is_mention!.type, .event)
|
||||
XCTAssertEqual(ref.is_mention!.ref.ref_id, "event_id")
|
||||
XCTAssertEqual(ref.is_mention?.type, .event)
|
||||
XCTAssertEqual(ref.is_mention?.ref.ref_id, "event_id")
|
||||
}
|
||||
|
||||
func testUrlAnchorsAreNotHashtags() {
|
||||
@ -96,11 +96,11 @@ class ReplyTests: XCTestCase {
|
||||
XCTAssertNotNil(event_refs[0].is_thread_id)
|
||||
XCTAssertNotNil(event_refs[0].is_reply)
|
||||
XCTAssertNotNil(event_refs[0].is_direct_reply)
|
||||
XCTAssertEqual(event_refs[0].is_reply!.ref_id, "thread_id")
|
||||
XCTAssertEqual(event_refs[0].is_thread_id!.ref_id, "thread_id")
|
||||
XCTAssertEqual(event_refs[0].is_reply?.ref_id, "thread_id")
|
||||
XCTAssertEqual(event_refs[0].is_thread_id?.ref_id, "thread_id")
|
||||
XCTAssertNotNil(event_refs[1].is_mention)
|
||||
XCTAssertEqual(event_refs[1].is_mention!.type, .event)
|
||||
XCTAssertEqual(event_refs[1].is_mention!.ref.ref_id, "mentioned_id")
|
||||
XCTAssertEqual(event_refs[1].is_mention?.type, .event)
|
||||
XCTAssertEqual(event_refs[1].is_mention?.ref.ref_id, "mentioned_id")
|
||||
}
|
||||
|
||||
func testEmptyMention() throws {
|
||||
|
@ -64,6 +64,33 @@ class damusTests: XCTestCase {
|
||||
XCTAssertNotNil(parsed[0].is_text)
|
||||
}
|
||||
|
||||
func testParseUrl() {
|
||||
let parsed = parse_mentions(content: "a https://jb55.com b", tags: [])
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed.count, 3)
|
||||
XCTAssertEqual(parsed[1].is_url?.absoluteString, "https://jb55.com")
|
||||
}
|
||||
|
||||
func testParseUrlEnd() {
|
||||
let parsed = parse_mentions(content: "a https://jb55.com", tags: [])
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed.count, 2)
|
||||
XCTAssertEqual(parsed[0].is_text, "a ")
|
||||
XCTAssertEqual(parsed[1].is_url?.absoluteString, "https://jb55.com")
|
||||
}
|
||||
|
||||
func testParseUrlStart() {
|
||||
let parsed = parse_mentions(content: "https://jb55.com br", tags: [])
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed.count, 3)
|
||||
XCTAssertEqual(parsed[0].is_text, "")
|
||||
XCTAssertEqual(parsed[1].is_url?.absoluteString, "https://jb55.com")
|
||||
XCTAssertEqual(parsed[2].is_text, " br")
|
||||
}
|
||||
|
||||
func testParseMentionBlank() {
|
||||
let parsed = parse_mentions(content: "", tags: [["e", "event_id"]])
|
||||
|
||||
@ -91,9 +118,9 @@ class damusTests: XCTestCase {
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed.count, 3)
|
||||
XCTAssertEqual(parsed[0].is_text!, "some hashtag ")
|
||||
XCTAssertEqual(parsed[1].is_hashtag!, "bitcoin")
|
||||
XCTAssertEqual(parsed[2].is_text!, " derp")
|
||||
XCTAssertEqual(parsed[0].is_text, "some hashtag ")
|
||||
XCTAssertEqual(parsed[1].is_hashtag, "bitcoin")
|
||||
XCTAssertEqual(parsed[2].is_text, " derp")
|
||||
}
|
||||
|
||||
func testParseHashtagEnd() {
|
||||
@ -101,8 +128,8 @@ class damusTests: XCTestCase {
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed.count, 2)
|
||||
XCTAssertEqual(parsed[0].is_text!, "some hashtag ")
|
||||
XCTAssertEqual(parsed[1].is_hashtag!, "bitcoin")
|
||||
XCTAssertEqual(parsed[0].is_text, "some hashtag ")
|
||||
XCTAssertEqual(parsed[1].is_hashtag, "bitcoin")
|
||||
}
|
||||
|
||||
func testParseMentionOnlyText() {
|
||||
@ -110,7 +137,7 @@ class damusTests: XCTestCase {
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed.count, 1)
|
||||
XCTAssertEqual(parsed[0].is_text!, "there is no mention here")
|
||||
XCTAssertEqual(parsed[0].is_text, "there is no mention here")
|
||||
|
||||
guard case .text(let txt) = parsed[0] else {
|
||||
XCTAssertTrue(false)
|
||||
|
Loading…
Reference in New Issue
Block a user