iOS client for Grain grain.social
ios photography atproto
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: detect bare domain links in profile bios and descriptions

Adds a separate bare domain regex pass matching the web app's
RichText.svelte approach, so links like throne.com/user and
clarabelle.xyz are tappable without requiring https:// prefix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+12
+12
Grain/Views/Components/RichTextView.swift
··· 116 116 117 117 private func segmentsFromRegex(text: String) -> [Segment] { 118 118 let urlPattern = #"https?://[^\s<>\[\]()]+"# 119 + let bareDomainPattern = #"(?<![/@\w.])([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(/[^\s<>\[\]()]*)?"# 119 120 let mentionPattern = #"@([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?"# 120 121 let hashtagPattern = #"#(\p{L}[\p{L}\p{N}_]*)"# 121 122 ··· 132 133 if let range = Range(matchResult.range, in: text) { 133 134 let str = String(text[range]) 134 135 matches.append(Match(range: range, segment: .link(str, url: str))) 136 + } 137 + } 138 + } 139 + 140 + if let regex = try? NSRegularExpression(pattern: bareDomainPattern) { 141 + let nsRange = NSRange(text.startIndex..., in: text) 142 + for matchResult in regex.matches(in: text, range: nsRange) { 143 + if let range = Range(matchResult.range, in: text) { 144 + if matches.contains(where: { $0.range.overlaps(range) }) { continue } 145 + let str = String(text[range]) 146 + matches.append(Match(range: range, segment: .link(str, url: "https://\(str)"))) 135 147 } 136 148 } 137 149 }