mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 17:05:19 +00:00
* Remove link previews: link URLs inline\n\n- Delete LinkPreviewView and all references\n- Strip preview usage from ContentView\n- Make detected URLs tappable via .link attribute\n- Add MessageTextHelpers for tokens/length checks\n- Wire helpers into iOS/macOS targets * Peer list UX: match message colors, use map pin icon, stable ordering\n\n- Color list names and icons with same peer color as messages\n- Default icon mappin; teleported uses face.dashed (iOS)\n- Geohash: move teleported peers to bottom\n- Maintain stable order: append new peers, remove missing\n- Mesh list: replace state icons with colored mappin/person * Fix peer list build errors: remove ambiguous Set type, avoid guard in ViewBuilder, remove duplicate bindings, and simplify person lookup * Peer list: remove onChange expressions to avoid type-check issues; rely on ObservedObject updates * Peer lists: simplify view structure to satisfy SwiftUI type checker (replace Group with VStack, flatten body) * Peer lists: move ordering mutations to onAppear/onChange, keep body pure; fix result builder errors * Fix: remove trailing modifiers outside if/else to avoid ViewBuilder type issues * Color parity: fix seed cache to include color scheme; normalize Nostr seeds; switch to mappin.circle icon * Peer colors: ensure exact match with message colors\n\n- Mesh list uses same seed logic as messages (getNoiseKeyForShortID fallback)\n- Color cache keyed by theme; normalize nostr seeds\n- Icons: use mappin.and.ellipse (default) and face.dashed for teleported\n- Teleport tag: accept "teleported" in addition to "teleport" and presence events * Fix geohash color mismatch: populate nostrKeyMapping before building messages in resubscribe; also honor t,teleport tag for teleported state * Message actions: username tap opens sheet via clickable AttributedString; message tap inserts @mention; rename to 'direct message' * Cashu UX: suppress 'Show more' when message contains a Cashu token (chips handle rendering) * Cashu detection: broaden regex (allow '.') + shorter min length; avoid long-text fallback when Cashu present so chips render and no full blob * Geohash levels: rename region->province, country->region; update labels, precision, UI, manager mapping, tests; add Codable backward-compat for renamed cases * Fix braces in LocationChannel.swift: close enum before extension to satisfy file-scope declarations * Geohash links: make #geohash tappable and open that channel (bitchat://geohash/<gh>); handle in ContentView.onOpenURL with validation and selection * Underline tappable #geohash mentions for clarity * Geochat: sanitize timeline on channel switch to remove any blank-content entries (prevents blank rows) * Xcode project: sync sources after UI changes (remove LinkPreview, add helpers, update build refs) --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com>
46 lines
2.0 KiB
Swift
46 lines
2.0 KiB
Swift
import XCTest
|
|
@testable import bitchat
|
|
|
|
final class LocationChannelsTests: XCTestCase {
|
|
func testGeohashEncoderPrecisionMapping() {
|
|
// Sanity: known coords (Statue of Liberty approx)
|
|
let lat = 40.6892
|
|
let lon = -74.0445
|
|
let block = Geohash.encode(latitude: lat, longitude: lon, precision: GeohashChannelLevel.block.precision)
|
|
let neighborhood = Geohash.encode(latitude: lat, longitude: lon, precision: GeohashChannelLevel.neighborhood.precision)
|
|
let city = Geohash.encode(latitude: lat, longitude: lon, precision: GeohashChannelLevel.city.precision)
|
|
let region = Geohash.encode(latitude: lat, longitude: lon, precision: GeohashChannelLevel.province.precision)
|
|
let country = Geohash.encode(latitude: lat, longitude: lon, precision: GeohashChannelLevel.region.precision)
|
|
|
|
XCTAssertEqual(block.count, 7)
|
|
XCTAssertEqual(neighborhood.count, 6)
|
|
XCTAssertEqual(city.count, 5)
|
|
XCTAssertEqual(region.count, 4)
|
|
XCTAssertEqual(country.count, 2)
|
|
|
|
// All prefixes must match progressively
|
|
XCTAssertTrue(block.hasPrefix(neighborhood))
|
|
XCTAssertTrue(neighborhood.hasPrefix(city))
|
|
XCTAssertTrue(city.hasPrefix(region))
|
|
XCTAssertTrue(region.hasPrefix(country))
|
|
}
|
|
|
|
func testNostrGeohashFilterEncoding() throws {
|
|
let gh = "u4pruy"
|
|
let filter = NostrFilter.geohashEphemeral(gh)
|
|
let data = try JSONEncoder().encode(filter)
|
|
let json = String(data: data, encoding: .utf8) ?? ""
|
|
// Expect kinds includes 20000 and tag filter '#g':[gh]
|
|
XCTAssertTrue(json.contains("20000"))
|
|
XCTAssertTrue(json.contains("\"#g\":[\"\(gh)\"]"))
|
|
}
|
|
|
|
func testPerGeohashIdentityDeterministic() throws {
|
|
// Derive twice for same geohash; should be identical
|
|
let gh = "u4pruy"
|
|
let id1 = try NostrIdentityBridge.deriveIdentity(forGeohash: gh)
|
|
let id2 = try NostrIdentityBridge.deriveIdentity(forGeohash: gh)
|
|
XCTAssertEqual(id1.publicKeyHex, id2.publicKeyHex)
|
|
}
|
|
}
|