mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 20:05:22 +00:00
Replaces the share-extension handoff that auto-sent shared text/URLs into the current channel with a validated, single-slot 24h envelope that shows the destination and a bounded preview and requires an explicit tap to copy into the composer — it never sends. Rejects malformed/oversized/control-character/non-HTTP(S)/expired payloads (including bidi-override U+202E), and clears on consume/cancel/expiry/panic. Rebased onto main with Persian strings added for all new keys (30-locale coverage verified), plus a panic-recovery clear so an envelope staged during an interrupted wipe cannot survive relaunch.
76 lines
1.8 KiB
Swift
76 lines
1.8 KiB
Swift
import BitFoundation
|
|
import Combine
|
|
import Foundation
|
|
|
|
enum RuntimeScenePhase: String, Sendable, Equatable {
|
|
case active
|
|
case inactive
|
|
case background
|
|
}
|
|
|
|
enum TorLifecycleEvent: String, Sendable, Equatable {
|
|
case willStart
|
|
case willRestart
|
|
case didBecomeReady
|
|
case preferenceChanged
|
|
}
|
|
|
|
enum AppEvent: Sendable, Equatable {
|
|
case launched
|
|
case startupCompleted
|
|
case scenePhaseChanged(RuntimeScenePhase)
|
|
case openedURL(String)
|
|
case sharedContentReadyForReview(SharedContentKind)
|
|
case notificationOpened(peerID: PeerID?)
|
|
case deepLinkOpened(String)
|
|
case torLifecycleChanged(TorLifecycleEvent)
|
|
case nostrRelayConnectionChanged(Bool)
|
|
case terminationRequested
|
|
}
|
|
|
|
actor AppEventStream {
|
|
private var continuations: [UUID: AsyncStream<AppEvent>.Continuation] = [:]
|
|
|
|
func emit(_ event: AppEvent) {
|
|
for continuation in continuations.values {
|
|
continuation.yield(event)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/// Identity key for a direct conversation. Equality and hashing use the
|
|
/// canonical `id` only; `routingPeerID` carries the transport-level peer ID
|
|
/// the conversation is keyed under (see `ConversationID.directPeer`).
|
|
struct PeerHandle: Sendable, Identifiable {
|
|
let id: String
|
|
let routingPeerID: PeerID
|
|
}
|
|
|
|
extension PeerHandle: Equatable {
|
|
static func == (lhs: PeerHandle, rhs: PeerHandle) -> Bool {
|
|
lhs.id == rhs.id
|
|
}
|
|
}
|
|
|
|
extension PeerHandle: Hashable {
|
|
func hash(into hasher: inout Hasher) {
|
|
hasher.combine(id)
|
|
}
|
|
}
|
|
|
|
enum ConversationID: Hashable, Sendable {
|
|
case mesh
|
|
case geohash(String)
|
|
case direct(PeerHandle)
|
|
|
|
init(channelID: ChannelID) {
|
|
switch channelID {
|
|
case .mesh:
|
|
self = .mesh
|
|
case .location(let channel):
|
|
self = .geohash(channel.geohash.lowercased())
|
|
}
|
|
}
|
|
}
|