Replace the abandoned RN iOS path with a SwiftUI app (iOS 17+) that reuses the shared TipTap editor bundle, GRDB local mirror/outbox, and Android-aligned shell chrome for list, create, detail, and Me. Package the editor HTML in the app resources so Markdown renders, present edit from the workspace root with a UIKit FAB, and keep caret stable while typing.
48 lines
1.3 KiB
Swift
48 lines
1.3 KiB
Swift
import Foundation
|
|
|
|
extension URL {
|
|
/// Strip trailing slashes for stable instance keys / API base URLs.
|
|
var edgeEverNormalizedBase: URL {
|
|
var absolute = absoluteString
|
|
while absolute.hasSuffix("/") {
|
|
absolute.removeLast()
|
|
}
|
|
return URL(string: absolute) ?? self
|
|
}
|
|
}
|
|
|
|
enum EdgeEverURLNormalizer {
|
|
static func normalizeInstanceURL(_ raw: String) throws -> URL {
|
|
var trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if trimmed.isEmpty {
|
|
throw EdgeEverURLError.empty
|
|
}
|
|
if !trimmed.contains("://") {
|
|
trimmed = "https://\(trimmed)"
|
|
}
|
|
guard var components = URLComponents(string: trimmed), let host = components.host, !host.isEmpty else {
|
|
throw EdgeEverURLError.invalid
|
|
}
|
|
components.fragment = nil
|
|
components.query = nil
|
|
guard let url = components.url else {
|
|
throw EdgeEverURLError.invalid
|
|
}
|
|
return url.edgeEverNormalizedBase
|
|
}
|
|
}
|
|
|
|
enum EdgeEverURLError: LocalizedError {
|
|
case empty
|
|
case invalid
|
|
|
|
var errorDescription: String? {
|
|
switch self {
|
|
case .empty:
|
|
return "Instance URL is required."
|
|
case .invalid:
|
|
return "Instance URL is invalid."
|
|
}
|
|
}
|
|
}
|