From 41ea56cbad563a446e2af4fb1a7c0ae13fe8cc90 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 13 Sep 2025 15:37:10 +0200 Subject: [PATCH 1/2] feature: add local translation using LLM with MLX - add MLXTranslationService for on-device translation - add MLXModelManager for model downloading and management - add unified TranslationService interface supporting iOS/macOS - integrate translation into ChatViewModel with translate/untranslate actions - update ContentView with translation UI controls - support almost any language (currently using gemma3-1B) - Add Package.swift dependencies for MLX framework Resolves need for privacy-preserving translation without internet dependency --- Package.swift | 6 +- bitchat/BitchatApp.swift | 3 + bitchat/LaunchScreen.storyboard | 40 -- bitchat/Services/MLXModelManager.swift | 396 +++++++++++++++++++ bitchat/Services/MLXTranslationService.swift | 274 +++++++++++++ bitchat/Services/TranslationService.swift | 300 ++++++++++++++ bitchat/ViewModels/ChatViewModel.swift | 140 +++++++ bitchat/Views/ContentView.swift | 73 ++++ 8 files changed, 1191 insertions(+), 41 deletions(-) delete mode 100644 bitchat/LaunchScreen.storyboard create mode 100644 bitchat/Services/MLXModelManager.swift create mode 100644 bitchat/Services/MLXTranslationService.swift create mode 100644 bitchat/Services/TranslationService.swift diff --git a/Package.swift b/Package.swift index c3e4b26cb..cc7034753 100644 --- a/Package.swift +++ b/Package.swift @@ -16,12 +16,16 @@ let package = Package( ], dependencies:[ .package(url: "https://github.com/21-DOT-DEV/swift-secp256k1", exact: "0.21.1"), + .package(url: "https://github.com/ml-explore/mlx-swift", from: "0.18.0"), ], targets: [ .executableTarget( name: "bitchat", dependencies: [ - .product(name: "P256K", package: "swift-secp256k1") + .product(name: "P256K", package: "swift-secp256k1"), + .product(name: "MLX", package: "mlx-swift"), + .product(name: "MLXNN", package: "mlx-swift"), + .product(name: "MLXLMCommon", package: "mlx-swift"), ], path: "bitchat", exclude: [ diff --git a/bitchat/BitchatApp.swift b/bitchat/BitchatApp.swift index db060dcba..1e811bff3 100644 --- a/bitchat/BitchatApp.swift +++ b/bitchat/BitchatApp.swift @@ -43,6 +43,9 @@ struct BitchatApp: App { } #if os(iOS) appDelegate.chatViewModel = chatViewModel + Task.detached { + await TranslationService.shared.prepareTranslation() + } #elseif os(macOS) appDelegate.chatViewModel = chatViewModel #endif diff --git a/bitchat/LaunchScreen.storyboard b/bitchat/LaunchScreen.storyboard deleted file mode 100644 index 7d2b247a4..000000000 --- a/bitchat/LaunchScreen.storyboard +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bitchat/Services/MLXModelManager.swift b/bitchat/Services/MLXModelManager.swift new file mode 100644 index 000000000..f30124488 --- /dev/null +++ b/bitchat/Services/MLXModelManager.swift @@ -0,0 +1,396 @@ +import Foundation + +#if os(iOS) +import UIKit +import MLX +import MLXNN +import MLXLLM +import MLXLMCommon + +@available(iOS 16.0, *) +class MLXModelManager { + static let shared = MLXModelManager() + + private let fileManager = FileManager.default + private var isCurrentlyLoading = false + private let loadingLock = NSLock() + + private struct ModelConfig { + let identifier: String + let huggingFaceRepo: String + let localName: String + let sizeInMB: Int + } + + private let defaultModel = ModelConfig( + identifier: "gemma-3-1b-it", + huggingFaceRepo: "mlx-community/gemma-3-1b-it-4bit", + localName: "gemma-3-1b-it-4bit", + sizeInMB: 1200 + ) + + private var modelDirectory: URL { + let documentsPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first! + return documentsPath.appendingPathComponent("MLXModels") + } + + private init() { + createModelDirectoryIfNeeded() + } + + private func createModelDirectoryIfNeeded() { + if !fileManager.fileExists(atPath: modelDirectory.path) { + try? fileManager.createDirectory(at: modelDirectory, withIntermediateDirectories: true) + } + } + + var isModelAvailable: Bool { + return checkModelExists(modelId: defaultModel.huggingFaceRepo) + } + + var estimatedModelSize: Int64 { + return Int64(defaultModel.sizeInMB * 1024 * 1024) + } + + func ensureSpaceForModel() throws { + guard hasEnoughSpaceForModel() else { + throw MLXModelError.insufficientSpace + } + } + + func loadModel() async throws -> ModelContainer { + loadingLock.lock() + defer { loadingLock.unlock() } + + if isCurrentlyLoading { + while isCurrentlyLoading { + loadingLock.unlock() + try await Task.sleep(nanoseconds: 100_000_000) + loadingLock.lock() + } + } + + isCurrentlyLoading = true + defer { isCurrentlyLoading = false } + + do { + let currentModelExists = checkModelExists(modelId: defaultModel.huggingFaceRepo) + + if !currentModelExists { + try ensureSpaceForModel() + await clearAllModelsExcept(keepModel: defaultModel.huggingFaceRepo) + } + + MLX.GPU.set(cacheLimit: 2048 * 1024 * 1024) + + let modelConfig = ModelConfiguration(id: self.defaultModel.huggingFaceRepo) + + var lastLoggedProgress = -1 + let modelContainer = try await LLMModelFactory.shared.loadContainer(configuration: modelConfig) { progress in + if !currentModelExists { + let currentProgress = Int(progress.fractionCompleted * 100) + if currentProgress >= lastLoggedProgress + 10 { + print("Download progress: \(currentProgress)%") + lastLoggedProgress = currentProgress + } + } + } + + return modelContainer + } catch { + throw MLXModelError.loadFailed(error) + } + } + + private func checkModelExists(modelId: String) -> Bool { + let cacheDirectories = getMLXCacheDirectories() + let possibleNames = [ + modelId.replacingOccurrences(of: "/", with: "--"), + modelId.replacingOccurrences(of: "/", with: "_"), + String(modelId.split(separator: "/").last ?? ""), + modelId + ] + + for directory in cacheDirectories { + guard fileManager.fileExists(atPath: directory.path) else { continue } + + do { + let contents = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.isDirectoryKey]) + + for item in contents { + let itemName = item.lastPathComponent + + for possibleName in possibleNames { + if !possibleName.isEmpty && (itemName.contains(possibleName) || itemName.hasPrefix(possibleName)) { + if let isDirectory = try? item.resourceValues(forKeys: [.isDirectoryKey]).isDirectory, + isDirectory { + let modelFiles = try? fileManager.contentsOfDirectory(at: item, includingPropertiesForKeys: nil) + let hasModelFiles = modelFiles?.contains { file in + let fileName = file.lastPathComponent + return fileName.hasSuffix(".safetensors") || + fileName.hasSuffix(".gguf") || + fileName == "config.json" || + fileName == "tokenizer.json" || + fileName.contains("model") + } ?? false + + if hasModelFiles { + return true + } + } + } + } + } + } catch { + continue + } + } + + return false + } + + private func getMLXCacheDirectories() -> [URL] { + var directories: [URL] = [] + + directories.append(modelDirectory) + + if let documentsPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first { + let libraryPath = documentsPath.deletingLastPathComponent() + let cachesPath = libraryPath.appendingPathComponent("Library").appendingPathComponent("Caches") + let appSupportPath = libraryPath.appendingPathComponent("Library").appendingPathComponent("Application Support") + + // Common MLX cache locations + directories.append(cachesPath.appendingPathComponent("models")) + directories.append(cachesPath.appendingPathComponent("MLX")) + directories.append(cachesPath.appendingPathComponent("huggingface").appendingPathComponent("hub")) + directories.append(cachesPath.appendingPathComponent("LLMModelFactory")) + directories.append(appSupportPath.appendingPathComponent("MLX")) + + // Dynamic discovery of MLX-related directories + if fileManager.fileExists(atPath: cachesPath.path) { + do { + let cacheContents = try fileManager.contentsOfDirectory(at: cachesPath, includingPropertiesForKeys: [.isDirectoryKey]) + for item in cacheContents { + let itemName = item.lastPathComponent.lowercased() + if itemName.contains("mlx") || itemName.contains("llm") { + directories.append(item) + } + } + } catch { + // Continue if cache scan fails + } + } + } + + return Array(Set(directories)) + } + + private func clearAllModelsExcept(keepModel: String?) async { + let cacheDirectories = getMLXCacheDirectories() + + for directory in cacheDirectories { + await clearDirectoryExcept(directory: directory, keepModel: keepModel) + } + + MLX.GPU.clearCache() + } + + private func clearDirectoryExcept(directory: URL, keepModel: String?) async { + guard fileManager.fileExists(atPath: directory.path) else { return } + + do { + let contents = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.isDirectoryKey]) + + for item in contents { + var shouldKeep = false + + if let keepModelId = keepModel { + let itemName = item.lastPathComponent.lowercased() + let possibleKeepNames = [ + keepModelId.replacingOccurrences(of: "/", with: "--").lowercased(), + keepModelId.replacingOccurrences(of: "/", with: "_").lowercased(), + String(keepModelId.split(separator: "/").last ?? "").lowercased(), + keepModelId.lowercased() + ] + + shouldKeep = possibleKeepNames.contains { possibleName in + !possibleName.isEmpty && (itemName.contains(possibleName) || itemName.hasPrefix(possibleName)) + } + + if !shouldKeep { + if let isDirectory = try? item.resourceValues(forKeys: [.isDirectoryKey]).isDirectory, isDirectory { + let subItems = try? fileManager.contentsOfDirectory(at: item, includingPropertiesForKeys: nil) + let containsOurModel = subItems?.contains { subItem in + let subItemName = subItem.lastPathComponent.lowercased() + return possibleKeepNames.contains { possibleName in + !possibleName.isEmpty && subItemName.contains(possibleName) + } + } ?? false + + if containsOurModel { + shouldKeep = true + } + } + } + } + + if !shouldKeep { + try? fileManager.removeItem(at: item) + } + } + + if directory != modelDirectory { + let remainingContents = try? fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil) + if remainingContents?.isEmpty == true { + try? fileManager.removeItem(at: directory) + } + } + } catch { + // Continue if directory clearing fails + } + } + + private func getAvailableSpace() -> Int64 { + do { + let documentsPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first?.path ?? "/" + let attributes = try fileManager.attributesOfFileSystem(forPath: documentsPath) + + if let freeSize = attributes[.systemFreeSize] as? Int64 { + return freeSize + } else if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first { + let resourceValues = try documentsURL.resourceValues(forKeys: [.volumeAvailableCapacityKey]) + return Int64(resourceValues.volumeAvailableCapacity ?? 0) + } + return 0 + } catch { + return 0 + } + } + + func hasEnoughSpaceForModel() -> Bool { + let availableSpace = getAvailableSpace() + let requiredSpace = estimatedModelSize * 2 + return availableSpace > requiredSpace + } + + func getModelStatus() -> ModelStatus { + return ModelStatus( + isAvailable: isModelAvailable, + modelName: defaultModel.localName, + estimatedSizeMB: defaultModel.sizeInMB, + hasEnoughSpace: hasEnoughSpaceForModel(), + availableSpaceGB: Double(getAvailableSpace()) / (1024 * 1024 * 1024) + ) + } + + func getTotalCachedModelSize() -> Int64 { + var totalSize: Int64 = 0 + let cacheDirectories = getMLXCacheDirectories() + + for directory in cacheDirectories { + guard fileManager.fileExists(atPath: directory.path) else { continue } + totalSize += getDirectorySize(at: directory) + } + + return totalSize + } + + private func getDirectorySize(at url: URL) -> Int64 { + var totalSize: Int64 = 0 + + do { + let contents = try fileManager.contentsOfDirectory(at: url, includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey]) + + for item in contents { + let resourceValues = try item.resourceValues(forKeys: [.fileSizeKey, .isDirectoryKey]) + + if let isDirectory = resourceValues.isDirectory, isDirectory { + totalSize += getDirectorySize(at: item) + } else if let fileSize = resourceValues.fileSize { + totalSize += Int64(fileSize) + } + } + } catch { + // Continue if size calculation fails + } + + return totalSize + } + + func getCacheInfo() -> CacheInfo { + let totalCachedSize = getTotalCachedModelSize() + let availableSpace = getAvailableSpace() + let cacheDirectories = getMLXCacheDirectories() + + var directoryInfo: [String: Int64] = [:] + for directory in cacheDirectories { + if fileManager.fileExists(atPath: directory.path) { + directoryInfo[directory.path] = getDirectorySize(at: directory) + } + } + + return CacheInfo( + totalCachedSizeMB: Int(totalCachedSize / (1024 * 1024)), + availableSpaceGB: Double(availableSpace) / (1024 * 1024 * 1024), + cacheDirectories: directoryInfo, + currentModel: defaultModel.huggingFaceRepo + ) + } + + #if DEBUG + func debugCacheDirectories() { + print("MLX Cache Analysis") + let cacheDirectories = getMLXCacheDirectories() + + for directory in cacheDirectories { + guard fileManager.fileExists(atPath: directory.path) else { continue } + + do { + let contents = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.isDirectoryKey]) + if !contents.isEmpty { + print("📂 \(directory.lastPathComponent): \(contents.count) items") + } + } catch { + continue + } + } + + print("Current model: \(defaultModel.huggingFaceRepo)") + print("Model cached: \(checkModelExists(modelId: defaultModel.huggingFaceRepo))") + } + #endif +} + +struct ModelStatus { + let isAvailable: Bool + let modelName: String + let estimatedSizeMB: Int + let hasEnoughSpace: Bool + let availableSpaceGB: Double +} + +struct CacheInfo { + let totalCachedSizeMB: Int + let availableSpaceGB: Double + let cacheDirectories: [String: Int64] + let currentModel: String +} + +enum MLXModelError: Error, LocalizedError { + case loadFailed(Error) + case insufficientSpace + case modelNotFound + + var errorDescription: String? { + switch self { + case .loadFailed(let error): + return "Model loading failed: \(error.localizedDescription)" + case .insufficientSpace: + return "Insufficient storage space for model" + case .modelNotFound: + return "Translation model not found" + } + } +} + +#endif diff --git a/bitchat/Services/MLXTranslationService.swift b/bitchat/Services/MLXTranslationService.swift new file mode 100644 index 000000000..3361ee7fa --- /dev/null +++ b/bitchat/Services/MLXTranslationService.swift @@ -0,0 +1,274 @@ +import Foundation + +#if os(iOS) +import UIKit +import MLX +import MLXNN +import MLXLLM +import MLXLMCommon + +@available(iOS 16.0, *) +class MLXTranslationService { + static let shared = MLXTranslationService() + + private var modelContainer: ModelContainer? + private var isModelLoaded = false + private let modelManager = MLXModelManager.shared + + private var isLoadingModel = false + private let loadingLock = NSLock() + + private let maxTokens = 500 + private let temperature: Float = 0.0 + + private init() {} + + private func loadModel() async throws { + guard !isModelLoaded else { return } + + loadingLock.lock() + defer { loadingLock.unlock() } + + if isLoadingModel { + while isLoadingModel { + loadingLock.unlock() + try await Task.sleep(nanoseconds: 100_000_000) + loadingLock.lock() + } + if isModelLoaded { return } + } + + isLoadingModel = true + defer { isLoadingModel = false } + + do { + let modelStatus = modelManager.getModelStatus() + if !modelStatus.hasEnoughSpace { + let storageInfo = getStorageRequirements() + print("Insufficient storage: need \(String(format: "%.1f", storageInfo.needsSpace)) GB more") + throw MLXTranslationError.insufficientMemory + } + + let container = try await modelManager.loadModel() + self.modelContainer = container + self.isModelLoaded = true + print("MLX translation model loaded") + } catch let error as MLXTranslationError { + self.isModelLoaded = false + throw error + } catch { + self.isModelLoaded = false + + if let mlxError = error as? MLXModelError { + switch mlxError { + case .insufficientSpace: + throw MLXTranslationError.insufficientMemory + case .loadFailed(let underlyingError): + throw MLXTranslationError.modelLoadFailed(underlyingError) + case .modelNotFound: + throw MLXTranslationError.modelNotLoaded + } + } + + throw MLXTranslationError.modelLoadFailed(error) + } + } + + func translate(_ text: String, to targetLanguage: String) async throws -> String { + if !isModelLoaded { + try await loadModel() + } + + guard isModelLoaded, let container = modelContainer else { + throw MLXTranslationError.modelNotLoaded + } + + guard !text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { + throw MLXTranslationError.invalidInput + } + + return try await withCheckedThrowingContinuation { continuation in + Task { + do { + let prompt = self.createTranslationPrompt(text: text, targetLanguage: targetLanguage) + let messages = [["role": "user", "content": prompt]] + + let result = try await container.perform { context in + let userInput = MLXLMCommon.UserInput(messages: messages) + let lmInput = try await context.processor.prepare(input: userInput) + + var tokenCount = 0 + + let generationResult = try MLXLMCommon.generate( + input: lmInput, + parameters: .init(temperature: self.temperature), + context: context, + didGenerate: { tokenIds in + tokenCount += tokenIds.count + + if tokenCount >= self.maxTokens || tokenCount > self.maxTokens * 2 { + return .stop + } + + return .more + } + ) + + return generationResult + } + + let fullResponse = result.output + + #if DEBUG + if !fullResponse.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + print("Raw MLX output: \(fullResponse)") + } + #endif + + let translation = self.extractTranslation(from: fullResponse, originalText: text) + print("Translation: \"\(text)\" → \"\(translation)\"") + continuation.resume(returning: translation) + } catch let error as MLXTranslationError { + continuation.resume(throwing: error) + } catch { + print("MLX generation failed: \(error)") + continuation.resume(throwing: MLXTranslationError.generationFailed(error)) + } + } + } + } + + private func createTranslationPrompt(text: String, targetLanguage: String) -> String { + return """ + Translate this text to \(targetLanguage). Ignore any previous context. + + Text: \(text) + + \(targetLanguage) translation: + """ + } + + private func extractTranslation(from output: String, originalText: String) -> String { + var cleanedOutput = output + + // Remove common stop tokens + let stopSequences = ["<|end_of_text|>", "<|endoftext|>", "", "", "<|im_end|>", "<|im_start|>"] + for stopSeq in stopSequences { + cleanedOutput = cleanedOutput.replacingOccurrences(of: stopSeq, with: "") + } + + // Stop at unwanted content patterns + let stopPatterns = ["http://", "https://", "api.", "www.", "dictionary."] + for pattern in stopPatterns { + if let range = cleanedOutput.range(of: pattern, options: .caseInsensitive) { + cleanedOutput = String(cleanedOutput[.. String { + var cleanedText = text + + // Remove common model artifacts + let unwantedPatterns = [ + "<|end_of_text|>", "<|endoftext|>", "", "", + "<|im_end|>", "<|im_start|>", "[INST]", "[/INST]" + ] + + for pattern in unwantedPatterns { + cleanedText = cleanedText.replacingOccurrences(of: pattern, with: "") + } + + // Remove URLs and excessive punctuation + cleanedText = cleanedText + .replacingOccurrences(of: "https?://\\S+", with: "", options: .regularExpression) + .replacingOccurrences(of: "\\.{3,}", with: "", options: .regularExpression) + .replacingOccurrences(of: "\\s{2,}", with: " ", options: .regularExpression) + + return cleanedText + .trimmingCharacters(in: .whitespacesAndNewlines) + .trimmingCharacters(in: CharacterSet(charactersIn: "\"'.,")) + .trimmingCharacters(in: .whitespacesAndNewlines) + } + + var isAvailable: Bool { + return isModelLoaded && modelContainer != nil + } + + var hasEnoughStorageSpace: Bool { + return modelManager.getModelStatus().hasEnoughSpace + } + + func getStorageRequirements() -> (required: Double, available: Double, needsSpace: Double) { + let status = modelManager.getModelStatus() + let requiredGB = Double(status.estimatedSizeMB * 2) / 1024.0 + let availableGB = status.availableSpaceGB + let needsGB = max(0, requiredGB - availableGB) + + return (required: requiredGB, available: availableGB, needsSpace: needsGB) + } + + func prepareModel() async throws { + do { + try await loadModel() + } catch { + throw MLXTranslationError.modelPreparationFailed(error) + } + } + + func getModelStatus() -> ModelStatus { + return modelManager.getModelStatus() + } +} + +enum MLXTranslationError: Error, LocalizedError { + case modelNotLoaded + case modelLoadFailed(Error) + case generationFailed(Error) + case modelPreparationFailed(Error) + case invalidInput + case insufficientMemory + + var errorDescription: String? { + switch self { + case .modelNotLoaded: + return "Translation model is not loaded" + case .modelLoadFailed(let error): + return "Failed to load translation model: \(error.localizedDescription)" + case .generationFailed(let error): + return "Translation generation failed: \(error.localizedDescription)" + case .modelPreparationFailed(let error): + return "Failed to prepare translation model: \(error.localizedDescription)" + case .invalidInput: + return "Invalid input text for translation" + case .insufficientMemory: + return "Insufficient storage space for translation model (~2.4 GB required)" + } + } +} + +#endif diff --git a/bitchat/Services/TranslationService.swift b/bitchat/Services/TranslationService.swift new file mode 100644 index 000000000..9389a8676 --- /dev/null +++ b/bitchat/Services/TranslationService.swift @@ -0,0 +1,300 @@ +import Foundation + +#if os(iOS) +import UIKit +#elseif os(macOS) +import AppKit +#endif + +@MainActor +class TranslationService: ObservableObject { + static let shared = TranslationService() + + private var translationCache: [String: String] = [:] + private var translatingMessages: Set = [] + + // Platform-specific translation services + #if os(iOS) + @available(iOS 16.0, *) + private lazy var mlxService: MLXTranslationService = { + return MLXTranslationService.shared + }() + #endif + + @Published var preferredLanguage: String = "English" { + didSet { + UserDefaults.standard.set(preferredLanguage, forKey: "preferredTranslationLanguage") + } + } + + private init() { + self.preferredLanguage = UserDefaults.standard.string(forKey: "preferredTranslationLanguage") ?? "English" + } + + func translateText(_ text: String) async -> String { + return await translateTo(text, targetLanguage: preferredLanguage) + } + + func translateTo(_ text: String, targetLanguage: String) async -> String { + let cleanText = extractMessageContent(from: text) + let cacheKey = "\(cleanText)_\(targetLanguage)" + + if let cached = translationCache[cacheKey] { + return replaceMessageContent(in: text, with: cached) + } + + if translatingMessages.contains(cacheKey) { + return text + } + + translatingMessages.insert(cacheKey) + defer { translatingMessages.remove(cacheKey) } + + do { + let translated = try await performTranslation(cleanText, targetLanguage: targetLanguage) + translationCache[cacheKey] = translated + return replaceMessageContent(in: text, with: translated) + } catch { + print("Translation failed: \(error)") + return text + } + } + + func isTranslated(_ text: String) -> Bool { + let cleanText = extractMessageContent(from: text) + let cacheKey = "\(cleanText)_\(preferredLanguage)" + return translationCache[cacheKey] != nil + } + + var isTranslationAvailable: Bool { + #if os(iOS) + if #available(iOS 16.0, *) { + return mlxService.hasEnoughStorageSpace + } else { + return false + } + #elseif os(macOS) + return true // Ollama on macOS + #else + return false + #endif + } + + func getTranslationStatus() -> TranslationStatus { + #if os(iOS) + if #available(iOS 16.0, *) { + let storageInfo = mlxService.getStorageRequirements() + return TranslationStatus( + isAvailable: mlxService.hasEnoughStorageSpace, + platform: "iOS (MLX)", + requiresStorage: true, + storageRequired: storageInfo.required, + storageAvailable: storageInfo.available, + storageNeeded: storageInfo.needsSpace + ) + } else { + return TranslationStatus( + isAvailable: false, + platform: "iOS", + requiresStorage: false, + reason: "Requires iOS 16.0 or later" + ) + } + #elseif os(macOS) + return TranslationStatus( + isAvailable: true, + platform: "macOS (Ollama)", + requiresStorage: false + ) + #else + return TranslationStatus( + isAvailable: false, + platform: "Unsupported", + requiresStorage: false, + reason: "Platform not supported" + ) + #endif + } + + private func extractMessageContent(from formattedText: String) -> String { + var content = formattedText + + if let senderEndRange = content.range(of: "> ") { + content = String(content[senderEndRange.upperBound...]) + } + + if content.hasPrefix("* ") && content.contains(" * [") { + if let systemStartRange = content.range(of: "* "), + let systemEndRange = content.range(of: " * [") { + content = String(content[systemStartRange.upperBound.. String { + if originalText.hasPrefix("* ") && originalText.contains(" * [") { + if let systemEndRange = originalText.range(of: " * [") { + let timestampPart = String(originalText[systemEndRange.lowerBound...]) + return "* \(newContent) \(timestampPart)" + } + } + + if let senderEndRange = originalText.range(of: "> ") { + let senderPart = String(originalText[.. String { + #if os(iOS) + if #available(iOS 16.0, *) { + do { + return try await mlxService.translate(text, to: targetLanguage) + } catch let error as MLXTranslationError { + switch error { + case .insufficientMemory: + let storageInfo = mlxService.getStorageRequirements() + print("MLX translation unavailable: Insufficient storage space") + print("Required: \(String(format: "%.1f", storageInfo.required)) GB") + print("Available: \(String(format: "%.1f", storageInfo.available)) GB") + print("Need to free up: \(String(format: "%.1f", storageInfo.needsSpace)) GB") + case .modelLoadFailed(let underlyingError): + print("MLX translation unavailable: Model failed to load - \(underlyingError.localizedDescription)") + default: + print("MLX translation unavailable: \(error.localizedDescription)") + } + // Return original text if MLX fails + return text + } catch { + print("MLX translation not available on iOS: \(error)") + // Return original text if MLX fails + return text + } + } else { + print("Translation requires iOS 16.0+") + return text + } + #elseif os(macOS) + // Use Ollama on macOS + return try await performOllamaTranslation(text, targetLanguage: targetLanguage) + #else + // Fallback for other platforms + return try await performOllamaTranslation(text, targetLanguage: targetLanguage) + #endif + } + + private func performOllamaTranslation(_ text: String, targetLanguage: String) async throws -> String { + guard let url = URL(string: "http://localhost:11434/api/generate") else { + throw TranslationError.invalidURL + } + + let requestBody: [String: Any] = [ + "model": "zongwei/gemma3-translator:1b", + "prompt": "Translate to \(targetLanguage): \(text)", + "stream": false + ] + + let jsonData = try JSONSerialization.data(withJSONObject: requestBody) + + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.httpBody = jsonData + request.timeoutInterval = 30.0 + + let (data, response) = try await URLSession.shared.data(for: request) + + guard let httpResponse = response as? HTTPURLResponse, + httpResponse.statusCode == 200 else { + throw TranslationError.requestFailed + } + + guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any], + let response = json["response"] as? String else { + throw TranslationError.invalidResponse + } + + return response.trimmingCharacters(in: .whitespacesAndNewlines) + } + + func setPreferredLanguage(_ language: String) { + preferredLanguage = language + } + + func clearCache() { + translationCache.removeAll() + } + + var isAvailable: Bool { + #if os(iOS) + if #available(iOS 16.0, *) { + return mlxService.isAvailable + } + return false + #elseif os(macOS) + return true // Assume Ollama is available on macOS + #else + return false + #endif + } + + /// Prepare translation models if needed (useful for iOS MLX) + func prepareTranslation() async { + #if os(iOS) + if #available(iOS 16.0, *) { + do { + try await mlxService.prepareModel() + } catch { + print("Failed to prepare MLX translation model: \(error)") + } + } + #endif + } +} + +struct TranslationStatus { + let isAvailable: Bool + let platform: String + let requiresStorage: Bool + let storageRequired: Double? + let storageAvailable: Double? + let storageNeeded: Double? + let reason: String? + + init(isAvailable: Bool, platform: String, requiresStorage: Bool, storageRequired: Double? = nil, storageAvailable: Double? = nil, storageNeeded: Double? = nil, reason: String? = nil) { + self.isAvailable = isAvailable + self.platform = platform + self.requiresStorage = requiresStorage + self.storageRequired = storageRequired + self.storageAvailable = storageAvailable + self.storageNeeded = storageNeeded + self.reason = reason + } +} + +enum TranslationError: Error { + case invalidURL + case requestFailed + case invalidResponse +} diff --git a/bitchat/ViewModels/ChatViewModel.swift b/bitchat/ViewModels/ChatViewModel.swift index 05872bfc4..5cc4125b1 100644 --- a/bitchat/ViewModels/ChatViewModel.swift +++ b/bitchat/ViewModels/ChatViewModel.swift @@ -218,6 +218,9 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { // MARK: - Published Properties @Published var messages: [BitchatMessage] = [] + + @Published var translatedMessages: Set = [] // Set of message IDs that have been translated + @Published var translatingMessages: Set = [] // Set of message IDs currently being translated @Published var currentColorScheme: ColorScheme = .light private let maxMessages = TransportConfig.meshTimelineCap // Maximum messages before oldest are removed @Published var isConnected = false @@ -339,6 +342,10 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { @Published var autocompleteRange: NSRange? = nil @Published var selectedAutocompleteIndex: Int = 0 + @Published var showLanguageAlert = false + @Published var selectedMessageForLanguage: String? = nil + @Published var languageInput: String = "" + // Temporary property to fix compilation @Published var showPasswordPrompt = false @@ -3146,6 +3153,139 @@ final class ChatViewModel: ObservableObject, BitchatDelegate { return range.location + nickname.count + (nickname.hasPrefix("@") ? 1 : 2) } + @MainActor + func showLanguageSelectionForMessage(_ messageID: String) { + selectedMessageForLanguage = messageID + languageInput = TranslationService.shared.preferredLanguage + showLanguageAlert = true + } + + @MainActor + func confirmLanguageSelection() { + if !languageInput.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + TranslationService.shared.setPreferredLanguage(languageInput.trimmingCharacters(in: .whitespacesAndNewlines)) + } + showLanguageAlert = false + + if let messageID = selectedMessageForLanguage { + selectedMessageForLanguage = nil + Task { + await translateMessage(messageID) + } + } + } + + @MainActor + func translateMessage(_ messageID: String) async { + guard !translatedMessages.contains(messageID) && !translatingMessages.contains(messageID), + let message = findMessage(byID: messageID) else { + return + } + + translatingMessages.insert(messageID) + print("Translating... \(messageID)") + + let formattedText = formatMessageAsText(message, colorScheme: currentColorScheme) + let originalText = String(formattedText.characters[...]) + + let translatedText = await TranslationService.shared.translateText(originalText) + + let tempMessage = BitchatMessage( + id: message.id, + sender: message.sender, + content: extractContentFromTranslatedText(translatedText, originalMessage: message), + timestamp: message.timestamp, + isRelay: message.isRelay, + originalSender: message.originalSender, + isPrivate: message.isPrivate, + recipientNickname: message.recipientNickname, + senderPeerID: message.senderPeerID, + mentions: message.mentions, + deliveryStatus: message.deliveryStatus + ) + + // Format the temporary message to get properly styled AttributedString + let properlyFormattedText = formatMessageAsText(tempMessage, colorScheme: currentColorScheme) + + message.setCachedFormattedText(properlyFormattedText, isDark: currentColorScheme == .dark, isSelf: isMessageFromSelf(message)) + translatedMessages.insert(messageID) + translatingMessages.remove(messageID) + } + + /// Extract the translated content from the formatted translation service result + private func extractContentFromTranslatedText(_ translatedText: String, originalMessage: BitchatMessage) -> String { + // The TranslationService returns formatted text like "<@sender> translated_content [timestamp]" + // We need to extract just the translated content part + if originalMessage.sender == "system" { + // For system messages, extract content between "* " and " * [" + if translatedText.hasPrefix("* ") && translatedText.contains(" * [") { + if let startRange = translatedText.range(of: "* "), + let endRange = translatedText.range(of: " * [") { + return String(translatedText[startRange.upperBound.. " and " [" (or end if no timestamp) + if let senderEndRange = translatedText.range(of: "> ") { + var content = String(translatedText[senderEndRange.upperBound...]) + + // Remove timestamp if present + if let timestampRange = content.range(of: " [", options: .backwards) { + let possibleTimestamp = String(content[timestampRange.lowerBound...]) + if possibleTimestamp.hasSuffix("]") { + content = String(content[.. Bool { + return translatingMessages.contains(messageID) + } + + func isMessageTranslated(_ messageID: String) -> Bool { + return translatedMessages.contains(messageID) + } + + /// Helper to find a message by ID across all message collections + private func findMessage(byID messageID: String) -> BitchatMessage? { + // Check public messages + if let message = messages.first(where: { $0.id == messageID }) { + return message + } + + // Check private chats + for (_, chatMessages) in privateChats { + if let message = chatMessages.first(where: { $0.id == messageID }) { + return message + } + } + + return nil + } + + /// Helper to check if a message is from self + private func isMessageFromSelf(_ message: BitchatMessage) -> Bool { + if let spid = message.senderPeerID { + // In geohash channels, compare against our per-geohash nostr short ID + if case .location(let ch) = activeChannel, spid.hasPrefix("nostr:") { + if let myGeo = try? NostrIdentityBridge.deriveIdentity(forGeohash: ch.geohash) { + return spid == "nostr:\(myGeo.publicKeyHex.prefix(TransportConfig.nostrShortKeyDisplayLength))" + } + } + return spid == meshService.myPeerID + } + // Fallback by nickname + if message.sender == nickname { return true } + if message.sender.hasPrefix(nickname + "#") { return true } + return false + } + // MARK: - Message Formatting func getSenderColor(for message: BitchatMessage, colorScheme: ColorScheme) -> Color { diff --git a/bitchat/Views/ContentView.swift b/bitchat/Views/ContentView.swift index 921bebe78..829a7a1d1 100644 --- a/bitchat/Views/ContentView.swift +++ b/bitchat/Views/ContentView.swift @@ -308,6 +308,24 @@ struct ContentView: View { .lineLimit(isLong && !isExpanded ? TransportConfig.uiLongMessageLineLimit : nil) .frame(maxWidth: .infinity, alignment: .leading) + if message.sender != "system" { + TranslationButton( + messageId: message.id, + isTranslating: viewModel.isMessageTranslating(message.id), + isTranslated: viewModel.isMessageTranslated(message.id), + secondaryTextColor: secondaryTextColor, + onTap: { + Task { + await viewModel.translateMessage(message.id) + } + }, + onLongPress: { + viewModel.showLanguageSelectionForMessage(message.id) + } + ) + .padding(.leading, 4) + } + // Delivery status indicator for private messages if message.isPrivate && message.sender == viewModel.nickname, let status = message.deliveryStatus { @@ -1201,6 +1219,18 @@ struct ContentView: View { .onAppear { viewModel.isLocationChannelsSheetPresented = true } .onDisappear { viewModel.isLocationChannelsSheetPresented = false } } + .alert("Translation Language", isPresented: $viewModel.showLanguageAlert) { + TextField("Language (e.g., Spanish, French)", text: $viewModel.languageInput) + Button("Translate") { + viewModel.confirmLanguageSelection() + } + Button("Cancel", role: .cancel) { + viewModel.showLanguageAlert = false + viewModel.selectedMessageForLanguage = nil + } + } message: { + Text("Enter the language you want to translate to:") + } .alert("heads up", isPresented: $viewModel.showScreenshotPrivacyWarning) { Button("ok", role: .cancel) {} } message: { @@ -1508,3 +1538,46 @@ struct DeliveryStatusView: View { } } } + +struct TranslationButton: View { + let messageId: String + let isTranslating: Bool + let isTranslated: Bool + let secondaryTextColor: Color + let onTap: () -> Void + let onLongPress: () -> Void + + @State private var isPressed = false + @State private var longPressTriggered = false + + var body: some View { + Group { + if isTranslating { + ProgressView() + .scaleEffect(0.6) + .frame(width: 16, height: 16) + } else { + Image(systemName: isTranslated ? "globe.badge.chevron.backward" : "globe") + .font(.system(size: 18)) + .foregroundColor(isTranslated ? .blue : secondaryTextColor.opacity(0.6)) + } + } + .scaleEffect(isPressed ? 1.1 : 1.0) + .animation(.easeInOut(duration: 0.1), value: isPressed) + .accessibilityLabel(isTranslated ? "Translated" : "Translate") + .onTapGesture { + if !isTranslating && !longPressTriggered { + onTap() + } + longPressTriggered = false + } + .onLongPressGesture(minimumDuration: 1.0) { + if !isTranslating { + longPressTriggered = true + onLongPress() + } + } onPressingChanged: { pressing in + isPressed = pressing + } + } +} From 9ab1bb15bddccb8e0f0d983ed6b422bba2dace35 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 13 Sep 2025 16:51:33 +0200 Subject: [PATCH 2/2] fix build --- .../ios-arm64/tor-nolzma.framework/Info.plist | 28 + .../tor-nolzma.framework/Info.plist | 28 + Package.resolved | 72 + Package.swift | 9 +- bitchat.xcodeproj/project.pbxproj | 106 +- bitchat.xcodeproj/project.pbxproj.backup | 1522 +++++++++++++++++ bitchat/Info.plist.backup | 56 + bitchat/LaunchScreen.storyboard | 40 + bitchat/Services/MLXTranslationService.swift | 2 +- bitchat/bitchat-macOS.entitlements | 8 +- bitchat/bitchat.entitlements | 6 +- .../bitchatShareExtension.entitlements | 6 +- project.yml.backup | 236 +++ 13 files changed, 2085 insertions(+), 34 deletions(-) create mode 100644 Frameworks/tor-nolzma.xcframework/ios-arm64/tor-nolzma.framework/Info.plist create mode 100644 Frameworks/tor-nolzma.xcframework/macos-arm64/tor-nolzma.framework/Info.plist create mode 100644 bitchat.xcodeproj/project.pbxproj.backup create mode 100644 bitchat/Info.plist.backup create mode 100644 bitchat/LaunchScreen.storyboard create mode 100644 project.yml.backup diff --git a/Frameworks/tor-nolzma.xcframework/ios-arm64/tor-nolzma.framework/Info.plist b/Frameworks/tor-nolzma.xcframework/ios-arm64/tor-nolzma.framework/Info.plist new file mode 100644 index 000000000..b0044e4d5 --- /dev/null +++ b/Frameworks/tor-nolzma.xcframework/ios-arm64/tor-nolzma.framework/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + tor-nolzma + CFBundleIdentifier + org.torproject.tor-nolzma + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + tor-nolzma + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + MinimumOSVersion + 12.0 + CFBundleSupportedPlatforms + + iPhoneOS + + + diff --git a/Frameworks/tor-nolzma.xcframework/macos-arm64/tor-nolzma.framework/Info.plist b/Frameworks/tor-nolzma.xcframework/macos-arm64/tor-nolzma.framework/Info.plist new file mode 100644 index 000000000..d73de505e --- /dev/null +++ b/Frameworks/tor-nolzma.xcframework/macos-arm64/tor-nolzma.framework/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + tor-nolzma + CFBundleIdentifier + org.torproject.tor-nolzma + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + tor-nolzma + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + 13.0 + CFBundleSupportedPlatforms + + MacOSX + + + diff --git a/Package.resolved b/Package.resolved index d7f002137..399b8417b 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,68 @@ { "pins" : [ + { + "identity" : "gzipswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/1024jp/GzipSwift", + "state" : { + "revision" : "731037f6cc2be2ec01562f6597c1d0aa3fe6fd05", + "version" : "6.0.1" + } + }, + { + "identity" : "jinja", + "kind" : "remoteSourceControl", + "location" : "https://github.com/johnmai-dev/Jinja", + "state" : { + "revision" : "5c0a87846dfd36ca6621795ad2f09fdaab82b739", + "version" : "1.3.0" + } + }, + { + "identity" : "mlx-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ml-explore/mlx-swift", + "state" : { + "revision" : "96c0f69cf15f38abd6248bb71fca908171dab1d8", + "version" : "0.25.6" + } + }, + { + "identity" : "mlx-swift-examples", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ml-explore/mlx-swift-examples/", + "state" : { + "branch" : "main", + "revision" : "dddb0b3871390dd9dea8e7ff2c347cf7e74cec9d" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "0fbc8848e389af3bb55c182bc19ca9d5dc2f255b", + "version" : "1.4.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "8c0c0a8b49e080e54e5e328cc552821ff07cd341", + "version" : "1.2.1" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics", + "state" : { + "revision" : "bbadd4b853a33fd78c4ae977d17bb2af15eb3f2a", + "version" : "1.1.0" + } + }, { "identity" : "swift-secp256k1", "kind" : "remoteSourceControl", @@ -8,6 +71,15 @@ "revision" : "8c62aba8a3011c9bcea232e5ee007fb0b34a15e2", "version" : "0.21.1" } + }, + { + "identity" : "swift-transformers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/huggingface/swift-transformers", + "state" : { + "revision" : "f000aa7aec0e78acd0211685e4094e1fca84cd8b", + "version" : "0.1.24" + } } ], "version" : 2 diff --git a/Package.swift b/Package.swift index cc7034753..ef1f423b2 100644 --- a/Package.swift +++ b/Package.swift @@ -16,16 +16,17 @@ let package = Package( ], dependencies:[ .package(url: "https://github.com/21-DOT-DEV/swift-secp256k1", exact: "0.21.1"), - .package(url: "https://github.com/ml-explore/mlx-swift", from: "0.18.0"), + .package(url: "https://github.com/ml-explore/mlx-swift-examples/", branch: "main"), ], targets: [ .executableTarget( name: "bitchat", dependencies: [ .product(name: "P256K", package: "swift-secp256k1"), - .product(name: "MLX", package: "mlx-swift"), - .product(name: "MLXNN", package: "mlx-swift"), - .product(name: "MLXLMCommon", package: "mlx-swift"), + .product(name: "MLX", package: "mlx-swift-examples"), + .product(name: "MLXNN", package: "mlx-swift-examples"), + .product(name: "MLXLLM", package: "mlx-swift-examples"), + .product(name: "MLXLMCommon", package: "mlx-swift-examples"), ], path: "bitchat", exclude: [ diff --git a/bitchat.xcodeproj/project.pbxproj b/bitchat.xcodeproj/project.pbxproj index acb412620..eb2391e72 100644 --- a/bitchat.xcodeproj/project.pbxproj +++ b/bitchat.xcodeproj/project.pbxproj @@ -146,6 +146,14 @@ B0CA7796B2B2AC2B33F84548 /* CompressionUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F149C43D1915831B60FE09 /* CompressionUtil.swift */; }; B45AD5BF95220A0289216D32 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E346DF8E026FD34EE3DD038 /* TestHelpers.swift */; }; B909706CD38FC56C0C8EB7BF /* IdentityModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05BA20BC0F123F1507C5C247 /* IdentityModels.swift */; }; + B9F96FE22E75BB64008282AE /* MLX in Frameworks */ = {isa = PBXBuildFile; productRef = MLXPROD1234567890ABCDEF01 /* MLX */; }; + B9F96FE32E75BB64008282AE /* MLXNN in Frameworks */ = {isa = PBXBuildFile; productRef = MLXPROD1234567890ABCDEF02 /* MLXNN */; }; + B9F96FE42E75BB64008282AE /* MLXLLM in Frameworks */ = {isa = PBXBuildFile; productRef = MLXPROD1234567890ABCDEF03 /* MLXLLM */; }; + B9F96FE52E75BB64008282AE /* MLXLMCommon in Frameworks */ = {isa = PBXBuildFile; productRef = MLXPROD1234567890ABCDEF04 /* MLXLMCommon */; }; + B9F96FE62E75BB64008282AE /* MLX in Frameworks */ = {isa = PBXBuildFile; productRef = MLXPROD1234567890ABCDEF01 /* MLX */; }; + B9F96FE72E75BB64008282AE /* MLXNN in Frameworks */ = {isa = PBXBuildFile; productRef = MLXPROD1234567890ABCDEF02 /* MLXNN */; }; + B9F96FE82E75BB64008282AE /* MLXLLM in Frameworks */ = {isa = PBXBuildFile; productRef = MLXPROD1234567890ABCDEF03 /* MLXLLM */; }; + B9F96FE92E75BB64008282AE /* MLXLMCommon in Frameworks */ = {isa = PBXBuildFile; productRef = MLXPROD1234567890ABCDEF04 /* MLXLMCommon */; }; BC4DC75F4FB823FF40569676 /* NoiseProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95DBE6A48626C5AE287245E /* NoiseProtocolTests.swift */; }; BCCFEDC1EBE59323C3C470BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A69677D382F1C3D5ED03F7D /* Assets.xcassets */; }; BCD0EBACD82AF5E55C2CB2B9 /* NostrRelayManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78595178957244CBDF7E79B6 /* NostrRelayManager.swift */; }; @@ -173,6 +181,12 @@ F455F011B3B648ADA233F998 /* BinaryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2136C3E22D02D4A8DBE7EAB /* BinaryProtocol.swift */; }; FB8819B4C84FAFEF5C36B216 /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 136696FC4436A02D98CE6A77 /* KeychainManager.swift */; }; FBC409E105493C491531B59A /* NostrProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E5A9FF4AEA8A923317ED26A /* NostrProtocol.swift */; }; + MLMB1A2B3C4D5E6F78901234 /* MLXModelManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = MLM01A2B3C4D5E6F78901234 /* MLXModelManager.swift */; }; + MLMC1A2B3C4D5E6F78901234 /* MLXModelManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = MLM01A2B3C4D5E6F78901234 /* MLXModelManager.swift */; }; + MLXB1A2B3C4D5E6F78901234 /* MLXTranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = MLX01A2B3C4D5E6F78901234 /* MLXTranslationService.swift */; }; + MLXC1A2B3C4D5E6F78901234 /* MLXTranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = MLX01A2B3C4D5E6F78901234 /* MLXTranslationService.swift */; }; + TSB01A2B3C4D5E6F78901234 /* TranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = TS001A2B3C4D5E6F78901234 /* TranslationService.swift */; }; + TSC01A2B3C4D5E6F78901234 /* TranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = TS001A2B3C4D5E6F78901234 /* TranslationService.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -308,6 +322,9 @@ FDC18D910D6FF2E8B1B6C885 /* SecureIdentityStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdentityStateManager.swift; sourceTree = ""; }; FE7CCF2BD78A3F3DAE6DA145 /* MockBLEService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBLEService.swift; sourceTree = ""; }; FF7AF93D874001FBD94C8306 /* bitchat-macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "bitchat-macOS.entitlements"; sourceTree = ""; }; + MLM01A2B3C4D5E6F78901234 /* MLXModelManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MLXModelManager.swift; sourceTree = ""; }; + MLX01A2B3C4D5E6F78901234 /* MLXTranslationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MLXTranslationService.swift; sourceTree = ""; }; + TS001A2B3C4D5E6F78901234 /* TranslationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationService.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -315,9 +332,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B9F96FE82E75BB64008282AE /* MLXLLM in Frameworks */, + B9F96FE62E75BB64008282AE /* MLX in Frameworks */, 0481A35B2E6D9BEF00FC845E /* libz.tbd in Frameworks */, 0481A3582E6D929E00FC845E /* tor-nolzma.xcframework in Frameworks */, + B9F96FE72E75BB64008282AE /* MLXNN in Frameworks */, 3EE336D150427F736F32B56C /* P256K in Frameworks */, + B9F96FE92E75BB64008282AE /* MLXLMCommon in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -325,6 +346,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B9F96FE52E75BB64008282AE /* MLXLMCommon in Frameworks */, + B9F96FE42E75BB64008282AE /* MLXLLM in Frameworks */, + B9F96FE32E75BB64008282AE /* MLXNN in Frameworks */, + B9F96FE22E75BB64008282AE /* MLX in Frameworks */, 0481A35D2E6DA18600FC845E /* libz.tbd in Frameworks */, 0481A3592E6D929E00FC845E /* tor-nolzma.xcframework in Frameworks */, 885BBED78092484A5B069461 /* P256K in Frameworks */, @@ -601,6 +626,9 @@ 394E8A1AC76EFAE352075BE9 /* NoiseEncryptionService.swift */, 3448F84BF86A42A3CC4A9379 /* NotificationService.swift */, 8C6FDA03416FDB2157A0A8C7 /* BLEService.swift */, + TS001A2B3C4D5E6F78901234 /* TranslationService.swift */, + MLX01A2B3C4D5E6F78901234 /* MLXTranslationService.swift */, + MLM01A2B3C4D5E6F78901234 /* MLXModelManager.swift */, ); path = Services; sourceTree = ""; @@ -636,6 +664,10 @@ name = bitchat_macOS; packageProductDependencies = ( B1D9136AA0083366353BFA2F /* P256K */, + MLXPROD1234567890ABCDEF01 /* MLX */, + MLXPROD1234567890ABCDEF02 /* MLXNN */, + MLXPROD1234567890ABCDEF03 /* MLXLLM */, + MLXPROD1234567890ABCDEF04 /* MLXLMCommon */, ); productName = bitchat_macOS; productReference = 8F3A7C058C2C8E1A06C8CF8B /* bitchat.app */; @@ -711,6 +743,10 @@ name = bitchat_iOS; packageProductDependencies = ( 4EB6BA1B8464F1EA38F4E286 /* P256K */, + MLXPROD1234567890ABCDEF01 /* MLX */, + MLXPROD1234567890ABCDEF02 /* MLXNN */, + MLXPROD1234567890ABCDEF03 /* MLXLLM */, + MLXPROD1234567890ABCDEF04 /* MLXLMCommon */, ); productName = bitchat_iOS; productReference = 96D0D41CA19EE5A772AA8434 /* bitchat.app */; @@ -723,26 +759,18 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1640; + LastUpgradeCheck = 1620; TargetAttributes = { 0576A29205865664C0937536 = { - DevelopmentTeam = L3N5LHJD5Y; ProvisioningStyle = Automatic; }; 47FF23248747DD7CB666CB91 = { - DevelopmentTeam = L3N5LHJD5Y; ProvisioningStyle = Automatic; }; 57CA17A36A2532A6CFF367BB = { - DevelopmentTeam = L3N5LHJD5Y; ProvisioningStyle = Automatic; }; 6CB97DF2EA57234CB3E563B8 = { - DevelopmentTeam = L3N5LHJD5Y; - ProvisioningStyle = Automatic; - }; - AF077EA0474EDEDE2C72716C = { - DevelopmentTeam = L3N5LHJD5Y; ProvisioningStyle = Automatic; }; }; @@ -759,6 +787,7 @@ minimizedProjectReferenceProxies = 1; packageReferences = ( B8C407587481BBB190741C93 /* XCRemoteSwiftPackageReference "swift-secp256k1" */, + MLX001234567890ABCDEF1234 /* XCRemoteSwiftPackageReference "mlx-swift-examples" */, ); projectDirPath = ""; projectRoot = ""; @@ -866,6 +895,9 @@ 049BD3962E4EC4F0001A566B /* CommandProcessor.swift in Sources */, D111988977C3BC246AB27FA4 /* SecureLogger.swift in Sources */, 8DE687D2EB5EB120868DBFB5 /* BLEService.swift in Sources */, + TSB01A2B3C4D5E6F78901234 /* TranslationService.swift in Sources */, + MLXB1A2B3C4D5E6F78901234 /* MLXTranslationService.swift in Sources */, + MLMB1A2B3C4D5E6F78901234 /* MLXModelManager.swift in Sources */, AA11BB22CC33DD44EE55FF66 /* MessageTextHelpers.swift in Sources */, E0A1B2C3D4E5F6012345678B /* GeoRelayDirectory.swift in Sources */, ); @@ -931,6 +963,9 @@ 049BD3922E4EC4F0001A566B /* CommandProcessor.swift in Sources */, EC5241969D2550B97629EBD0 /* SecureLogger.swift in Sources */, C165DD35BB8E9C327A3C2DA4 /* BLEService.swift in Sources */, + TSC01A2B3C4D5E6F78901234 /* TranslationService.swift in Sources */, + MLXC1A2B3C4D5E6F78901234 /* MLXTranslationService.swift in Sources */, + MLMC1A2B3C4D5E6F78901234 /* MLXModelManager.swift in Sources */, AA11BB22CC33DD44EE55FF67 /* MessageTextHelpers.swift in Sources */, E0A1B2C3D4E5F6012345678C /* GeoRelayDirectory.swift in Sources */, ); @@ -1012,6 +1047,7 @@ CODE_SIGNING_ALLOWED = YES; CODE_SIGNING_REQUIRED = YES; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = A4K7453KJ6; INFOPLIST_FILE = bitchatTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -1034,6 +1070,7 @@ CODE_SIGNING_ALLOWED = YES; CODE_SIGNING_REQUIRED = YES; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = A4K7453KJ6; INFOPLIST_FILE = bitchatTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -1058,6 +1095,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = A4K7453KJ6; INFOPLIST_FILE = bitchatTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1080,6 +1118,7 @@ CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; CODE_SIGN_ENTITLEMENTS = bitchatShareExtension/bitchatShareExtension.entitlements; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = A4K7453KJ6; INFOPLIST_FILE = bitchatShareExtension/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = bitchat; IPHONEOS_DEPLOYMENT_TARGET = 16.0; @@ -1089,7 +1128,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.3.4; - PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.ShareExtension; + PRODUCT_BUNDLE_IDENTIFIER = julian.chat.bitchat.ShareExtension; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -1110,6 +1149,7 @@ CODE_SIGN_ENTITLEMENTS = bitchat/bitchat.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = A4K7453KJ6; ENABLE_PREVIEWS = NO; INFOPLIST_FILE = bitchat/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = bitchat; @@ -1120,7 +1160,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.3.4; - PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; + PRODUCT_BUNDLE_IDENTIFIER = julian.chat.bitchat; PRODUCT_NAME = bitchat; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -1141,6 +1181,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = A4K7453KJ6; INFOPLIST_FILE = bitchatTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1164,7 +1205,8 @@ CODE_SIGNING_REQUIRED = YES; CODE_SIGN_ENTITLEMENTS = bitchat/bitchat.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = bitchat/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = bitchat; @@ -1175,8 +1217,9 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.3.4; - PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; + PRODUCT_BUNDLE_IDENTIFIER = julian.chat.bitchat; PRODUCT_NAME = bitchat; + PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -1198,6 +1241,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = A4K7453KJ6; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = bitchat/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = bitchat; @@ -1207,7 +1251,7 @@ ); MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.3.4; - PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; + PRODUCT_BUNDLE_IDENTIFIER = julian.chat.bitchat; PRODUCT_NAME = bitchat; REGISTER_APP_GROUPS = YES; SDKROOT = macosx; @@ -1287,6 +1331,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = A4K7453KJ6; ENABLE_PREVIEWS = NO; INFOPLIST_FILE = bitchat/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = bitchat; @@ -1296,7 +1341,7 @@ ); MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.3.4; - PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; + PRODUCT_BUNDLE_IDENTIFIER = julian.chat.bitchat; PRODUCT_NAME = bitchat; REGISTER_APP_GROUPS = YES; SDKROOT = macosx; @@ -1380,6 +1425,7 @@ CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; CODE_SIGN_ENTITLEMENTS = bitchatShareExtension/bitchatShareExtension.entitlements; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = A4K7453KJ6; INFOPLIST_FILE = bitchatShareExtension/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = bitchat; IPHONEOS_DEPLOYMENT_TARGET = 16.0; @@ -1389,7 +1435,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.3.4; - PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.ShareExtension; + PRODUCT_BUNDLE_IDENTIFIER = julian.chat.bitchat.ShareExtension; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -1468,6 +1514,14 @@ minimumVersion = 0.21.1; }; }; + MLX001234567890ABCDEF1234 /* XCRemoteSwiftPackageReference "mlx-swift-examples" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/ml-explore/mlx-swift-examples/"; + requirement = { + branch = main; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1481,6 +1535,26 @@ package = B8C407587481BBB190741C93 /* XCRemoteSwiftPackageReference "swift-secp256k1" */; productName = P256K; }; + MLXPROD1234567890ABCDEF01 /* MLX */ = { + isa = XCSwiftPackageProductDependency; + package = MLX001234567890ABCDEF1234 /* XCRemoteSwiftPackageReference "mlx-swift-examples" */; + productName = MLX; + }; + MLXPROD1234567890ABCDEF02 /* MLXNN */ = { + isa = XCSwiftPackageProductDependency; + package = MLX001234567890ABCDEF1234 /* XCRemoteSwiftPackageReference "mlx-swift-examples" */; + productName = MLXNN; + }; + MLXPROD1234567890ABCDEF03 /* MLXLLM */ = { + isa = XCSwiftPackageProductDependency; + package = MLX001234567890ABCDEF1234 /* XCRemoteSwiftPackageReference "mlx-swift-examples" */; + productName = MLXLLM; + }; + MLXPROD1234567890ABCDEF04 /* MLXLMCommon */ = { + isa = XCSwiftPackageProductDependency; + package = MLX001234567890ABCDEF1234 /* XCRemoteSwiftPackageReference "mlx-swift-examples" */; + productName = MLXLMCommon; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 475D96681D0EA0AE57A4E06E /* Project object */; diff --git a/bitchat.xcodeproj/project.pbxproj.backup b/bitchat.xcodeproj/project.pbxproj.backup new file mode 100644 index 000000000..6f35b852c --- /dev/null +++ b/bitchat.xcodeproj/project.pbxproj.backup @@ -0,0 +1,1522 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 026A4104B2B4588A88283DB5 /* PrivateChatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7C4CA419510D61C4FE47B2 /* PrivateChatManager.swift */; }; + 03B8B21F0F40DD0BF98D397B /* FragmentationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F2899A34E217B55CA551A29 /* FragmentationTests.swift */; }; + 064E1DB9D0CAD27E810828DD /* Info.plist.backup in Resources */ = {isa = PBXBuildFile; fileRef = 92B75E0496E71956EFA57A23 /* Info.plist.backup */; }; + 06882196B7AD8DB19593F712 /* OSLog+Categories.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3182D03ECBF0B8F881CA811E /* OSLog+Categories.swift */; }; + 07A73CEDC6D73043C6BE4D96 /* RelayController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFBF7162BBFF8184561FC64 /* RelayController.swift */; }; + 08AE06DD4B2F7049047F54E4 /* Geohash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28472CF48DAE200A6359E4A6 /* Geohash.swift */; }; + 0AE840940F21AFC07C226636 /* PrivateChatE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A262EDDC04B7D7B5E31F321 /* PrivateChatE2ETests.swift */; }; + 0B6F25559A21F8C69C8357C6 /* BinaryProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3CC6FA298729906109F61B /* BinaryProtocolTests.swift */; }; + 10E68BB889356219189E38EC /* BitchatApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF625BB3AD919322C01A46B2 /* BitchatApp.swift */; }; + 117F3B1B7D3D372F459DD998 /* NostrTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B4809E690DE48B9AEE36279 /* NostrTransport.swift */; }; + 132DF1E24B4E9C7DCDAD4376 /* FingerprintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9195CDC7EB236AFBC9A4D41A /* FingerprintView.swift */; }; + 17901751FD8010AFC8E750F2 /* bitchatShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 61F92EBA29C47C0FCC482F1F /* bitchatShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 1BD3295CA4D57C93C0A6522C /* FragmentationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F2899A34E217B55CA551A29 /* FragmentationTests.swift */; }; + 1C6705FCCFBFD24E74C73E7C /* CommandProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBE69984E3D1DC857CCD30A5 /* CommandProcessorTests.swift */; }; + 1CB54D76BBB605AD1F46C7D6 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 41A2626C2788F680C4C2B584 /* libz.tbd */; }; + 1D9674FA5F998503831DC281 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08E03AA0C63E97C91749AEC /* ContentView.swift */; }; + 1EF5C352D696311955010311 /* TranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D7577ACBFF5D167704FE7E /* TranslationService.swift */; }; + 20216EA81EFDC3632F8DB19F /* Transport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 556018DFA405705E5B00E982 /* Transport.swift */; }; + 292F514FE3A38B9E6704DBD6 /* GeoRelayDirectory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 259F214DC1197CD705F2FA7B /* GeoRelayDirectory.swift */; }; + 2E02905CBE350A2A168362E1 /* RelayController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFBF7162BBFF8184561FC64 /* RelayController.swift */; }; + 2EFCCAA297B16FA2B56747C7 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC75901A0F0073B5BB8356E7 /* TestConstants.swift */; }; + 33F91269305DEBFBC87489C9 /* PeerIDResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 321954679F94D55EBD0979DF /* PeerIDResolver.swift */; }; + 34542C84E4BFA98FC567B533 /* PeerDisplayNameResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C08ADEA9AEE89122C19D158 /* PeerDisplayNameResolver.swift */; }; + 34A341E43FC48F4C19B4F805 /* AutocompleteService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C39BB75BC8C2A36039F00613 /* AutocompleteService.swift */; }; + 37DDF3D09E2BAB92A5A8A9C1 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E346DF8E026FD34EE3DD038 /* TestHelpers.swift */; }; + 38EDDC049FD56B1BB1F14C91 /* IdentityModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05BA20BC0F123F1507C5C247 /* IdentityModels.swift */; }; + 39E236E0CA2C6F25D6E7E773 /* GeohashBookmarksStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E113B867C7531E4603F7118 /* GeohashBookmarksStoreTests.swift */; }; + 3A335CC28AE409554184936F /* BinaryProtocolPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D68C285B6A35B6C74F34529 /* BinaryProtocolPaddingTests.swift */; }; + 3EA8279F12C05DC2CE42AF05 /* MockBLEService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 568577CDDE5EC8B1A52F8CA0 /* MockBLEService.swift */; }; + 3EB848E57515ACA257FA05BC /* VerificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3346C98058A0B632BEB1B2 /* VerificationService.swift */; }; + 3EE336D150427F736F32B56C /* P256K in Frameworks */ = {isa = PBXBuildFile; productRef = B1D9136AA0083366353BFA2F /* P256K */; }; + 415145BEBD6D3E44C79FDB85 /* TransportConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B23F0624A8297F993ADF46 /* TransportConfig.swift */; }; + 429C568B42C2E4460045C795 /* CommandProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB10107B2A552E56B94C0AA4 /* CommandProcessor.swift */; }; + 438E81C9D07DABC9D6B86AD7 /* UnifiedPeerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D90CBA19E19728938700953D /* UnifiedPeerService.swift */; }; + 442FEE403846A040CF306CF9 /* OSLog+Categories.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3182D03ECBF0B8F881CA811E /* OSLog+Categories.swift */; }; + 44AD79B0EBD4678690E3DEB6 /* MessageDeduplicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0BF581F9D98C90EA9867BCF /* MessageDeduplicator.swift */; }; + 465F776816537C720DEB8600 /* BLEServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D911BB2E1F2CBF6BCB2D2F /* BLEServiceTests.swift */; }; + 4B747085D07A1BCE0F5BA612 /* BinaryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2136C3E22D02D4A8DBE7EAB /* BinaryProtocol.swift */; }; + 4DC6562C882AAC5F80DB1246 /* LaunchScreen.storyboard.ios in Resources */ = {isa = PBXBuildFile; fileRef = D112DB3FB47481D2837C763D /* LaunchScreen.storyboard.ios */; }; + 4DD1B1593CDE2FFD40546EDD /* tor-nolzma.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8AB4E248FB4EC311F56A1B41 /* tor-nolzma.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 4F2F1893E90C1B13D388CEA9 /* LocationChannelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B067FEF619D9D3D14782BA /* LocationChannelsTests.swift */; }; + 501BC56B1A08C0327A09AAF1 /* NoiseEncryptionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394E8A1AC76EFAE352075BE9 /* NoiseEncryptionService.swift */; }; + 5A0B730FCFACABE31EC6B402 /* LocationChannelManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935361F3BDD8F966DB207BF7 /* LocationChannelManager.swift */; }; + 5C93B4FDD0C448C3EDDBF8AE /* FavoritesPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419BFFF209EBA93F410E9E9F /* FavoritesPersistenceService.swift */; }; + 5EE49E150BBF0488E7473687 /* NoiseEncryptionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394E8A1AC76EFAE352075BE9 /* NoiseEncryptionService.swift */; }; + 61C81ED5F679D5E973EE0C07 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448F84BF86A42A3CC4A9379 /* NotificationService.swift */; }; + 65A68CE8842A98D9C655E0AA /* MessageRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D19E155BC6E68B1F331015 /* MessageRouter.swift */; }; + 6775EF2B889D38C1919239C4 /* BLEService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7229DDDE75E1FC21DE3947B /* BLEService.swift */; }; + 686441ABC2AF83EE98E6ECF2 /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC5AB43F4A8FB62C935CD74 /* IntegrationTests.swift */; }; + 68C4BE564735F6E7915274A2 /* SecureIdentityStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC18D910D6FF2E8B1B6C885 /* SecureIdentityStateManager.swift */; }; + 6A30AA6E36BEF48DAD666523 /* BLEService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7229DDDE75E1FC21DE3947B /* BLEService.swift */; }; + 6A85FC357ACD85DBD9020845 /* NostrRelayManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78595178957244CBDF7E79B6 /* NostrRelayManager.swift */; }; + 6C63FA98D59854C15C57B3D6 /* FingerprintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9195CDC7EB236AFBC9A4D41A /* FingerprintView.swift */; }; + 6D0D4A0B1D8B659DCBAE7C9C /* NoiseHandshakeCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D6A89B36A3D31E590B94E5 /* NoiseHandshakeCoordinator.swift */; }; + 6DE056E1EE9850E9FBF50157 /* BitchatProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229F17B68CFF7AB1BC91C847 /* BitchatProtocol.swift */; }; + 6DE24385FD4339F392927D0E /* TransportConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B23F0624A8297F993ADF46 /* TransportConfig.swift */; }; + 6E7761E21C99F28AE2F9BE5F /* BitchatApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF625BB3AD919322C01A46B2 /* BitchatApp.swift */; }; + 7241FFD6CFFB875B864FA223 /* InputValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90CB7A5CD1D1A521CD31F380 /* InputValidator.swift */; }; + 73F49A7476E8063041EA37E5 /* Packets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5190B5C75639CA5ECFEF16 /* Packets.swift */; }; + 749D8CF8A362B6CD0786782D /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448F84BF86A42A3CC4A9379 /* NotificationService.swift */; }; + 7576A357B278E5733E9D9F33 /* ChatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6B8F7B7D55092C2540A7996 /* ChatViewModel.swift */; }; + 765254F56997F01054699AC0 /* NoiseProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95DBE6A48626C5AE287245E /* NoiseProtocolTests.swift */; }; + 778592DC0729708A653D6B9A /* Transport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 556018DFA405705E5B00E982 /* Transport.swift */; }; + 78C3ED98EEF995D463F8179F /* LocationChannelManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935361F3BDD8F966DB207BF7 /* LocationChannelManager.swift */; }; + 7935EBDE0EC0E7CB93F14869 /* LocationChannelsSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F27C85DB05C7FB4ADDA3E11D /* LocationChannelsSheet.swift */; }; + 79831B2B4C682352326F3FB4 /* CTorHost.c in Sources */ = {isa = PBXBuildFile; fileRef = 04CD884F923001E260886E85 /* CTorHost.c */; }; + 7C19D2C9237111A7768E4AD4 /* LocationChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5670E854CD3772439BD68C2C /* LocationChannel.swift */; }; + 7DCA0DBCB8884E3B31C7BCE3 /* CompressionUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F149C43D1915831B60FE09 /* CompressionUtil.swift */; }; + 7DD72D928FF9DD3CA81B46B0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A69677D382F1C3D5ED03F7D /* Assets.xcassets */; }; + 8373C89F0B3247E875F905FA /* LocationChannelsSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F27C85DB05C7FB4ADDA3E11D /* LocationChannelsSheet.swift */; }; + 84D13329AB7EE1D65A37438A /* BitchatPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11186E29A064E8D210880E1B /* BitchatPeer.swift */; }; + 84E3F9B64FB7FB4A140BD0A8 /* BitchatPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11186E29A064E8D210880E1B /* BitchatPeer.swift */; }; + 85A86060AD95600D56FDF5BC /* PrivateChatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7C4CA419510D61C4FE47B2 /* PrivateChatManager.swift */; }; + 871D35F86A441ECA058880CE /* NostrEmbeddedBitChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3A1756A6D49A9B037F31A23 /* NostrEmbeddedBitChat.swift */; }; + 8851F08D88C5B1DE7B9F55C6 /* MockBluetoothMeshService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27328EE574221395B2B8E87 /* MockBluetoothMeshService.swift */; }; + 885BBED78092484A5B069461 /* P256K in Frameworks */ = {isa = PBXBuildFile; productRef = 4EB6BA1B8464F1EA38F4E286 /* P256K */; }; + 8A06DC9D003C4041E1C8884A /* GeohashBookmarksStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58950BE7879543DBF3F5339A /* GeohashBookmarksStore.swift */; }; + 8A14ADADF5CD7A79919CB655 /* NoiseSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AB6BE4ABD7F5088E9865E56 /* NoiseSession.swift */; }; + 8A641F15D219984EA205D715 /* TorURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761D68EC60DECAEA2513A30 /* TorURLSession.swift */; }; + 8C1AB0F2D48207E0755DA91A /* NoiseProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43613045E63D21D429396805 /* NoiseProtocol.swift */; }; + 8CE446C9364F54DF89E7A364 /* PublicChatE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22BF09A49010947CEFE45E2 /* PublicChatE2ETests.swift */; }; + 8D0196EAEE56973679F6A655 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC75901A0F0073B5BB8356E7 /* TestConstants.swift */; }; + 8F282E9CCA5AE1ECC001D2E4 /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC5AB43F4A8FB62C935CD74 /* IntegrationTests.swift */; }; + 8F737CE0435792CC2AD65FCB /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 136696FC4436A02D98CE6A77 /* KeychainManager.swift */; }; + 923027D6F2F417AFA2488127 /* BitchatProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229F17B68CFF7AB1BC91C847 /* BitchatProtocol.swift */; }; + 92D1CF17DF88EA298F6E5E8E /* NoiseSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AB6BE4ABD7F5088E9865E56 /* NoiseSession.swift */; }; + 92D34E7A07C990C8A815B0CE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08E03AA0C63E97C91749AEC /* ContentView.swift */; }; + 9361A868DCC81BB75DCD8170 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 2C82877869239E1E02FF9A88 /* README.md */; }; + 968181D255CA7A804340B4DA /* NostrProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C272F137CE00FC5A96E0CC06 /* NostrProtocolTests.swift */; }; + 9B51E9B63A3EA59B1A7874BD /* BinaryEncodingUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318B743C64628A125261163 /* BinaryEncodingUtils.swift */; }; + 9C7D287C8E67AAE576A5ECB7 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B378C16594575FCC7F9C75 /* ShareViewController.swift */; }; + 9CCF09F7527EC681A13FC246 /* NoiseSecurityConsiderations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43B4548DAFC9F7AA8873DA53 /* NoiseSecurityConsiderations.swift */; }; + 9F784B3AEC67201022B0F964 /* VerificationViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9D538710EEF999CC0C2E6F /* VerificationViews.swift */; }; + A0A1C26EFBFDD5B8EFEEDE57 /* PublicChatE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22BF09A49010947CEFE45E2 /* PublicChatE2ETests.swift */; }; + A0F4471D8974C5D3A317F6EC /* VerificationViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9D538710EEF999CC0C2E6F /* VerificationViews.swift */; }; + A1A32ACB18165DD04A5EC540 /* PeerID.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0569D3728519ED53CD9D7E /* PeerID.swift */; }; + A1D2AB3542F0C08C06AAA34B /* CTorHost.c in Sources */ = {isa = PBXBuildFile; fileRef = 04CD884F923001E260886E85 /* CTorHost.c */; }; + A7187D48B07C6857DE01D0ED /* NoiseProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43613045E63D21D429396805 /* NoiseProtocol.swift */; }; + A92C00F64DBFA588476765A6 /* NostrEmbeddedBitChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3A1756A6D49A9B037F31A23 /* NostrEmbeddedBitChat.swift */; }; + AA6E067DB034FC0FA23C28A9 /* BinaryProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3CC6FA298729906109F61B /* BinaryProtocolTests.swift */; }; + ABAF130D88561F4A646F0430 /* AppInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 763E0DBA9492A654FC0CDCB9 /* AppInfoView.swift */; }; + ACE2ED172C37F01561E50B71 /* FavoritesPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419BFFF209EBA93F410E9E9F /* FavoritesPersistenceService.swift */; }; + AD11E46940D742AEAF547EB2 /* AppInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 763E0DBA9492A654FC0CDCB9 /* AppInfoView.swift */; }; + AFB6AEFCABBE97441CB3102B /* BinaryEncodingUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318B743C64628A125261163 /* BinaryEncodingUtils.swift */; }; + AFF33EF44626EF0579D17EB1 /* NoiseHandshakeCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D6A89B36A3D31E590B94E5 /* NoiseHandshakeCoordinator.swift */; }; + B0CA7796B2B2AC2B33F84548 /* CompressionUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F149C43D1915831B60FE09 /* CompressionUtil.swift */; }; + B0DD5633DCD8895ACC289F9B /* GeohashBookmarksStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58950BE7879543DBF3F5339A /* GeohashBookmarksStore.swift */; }; + B27258BDC071D980D051B65F /* CommandProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB10107B2A552E56B94C0AA4 /* CommandProcessor.swift */; }; + B2ED9C2A5CDAFADC48237072 /* TranslationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D7577ACBFF5D167704FE7E /* TranslationService.swift */; }; + B313FE7E7263FF9BAD19B60B /* TorNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D69615DF03B207010A964D5 /* TorNotifications.swift */; }; + B416A6EFCC86F4FC08A73898 /* CommandProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBE69984E3D1DC857CCD30A5 /* CommandProcessorTests.swift */; }; + B45AD5BF95220A0289216D32 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E346DF8E026FD34EE3DD038 /* TestHelpers.swift */; }; + B8C285C2890920924A54FCBE /* TorNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D69615DF03B207010A964D5 /* TorNotifications.swift */; }; + B909706CD38FC56C0C8EB7BF /* IdentityModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05BA20BC0F123F1507C5C247 /* IdentityModels.swift */; }; + BC28BE9D0792847556BFC457 /* Info.plist.backup in Resources */ = {isa = PBXBuildFile; fileRef = 92B75E0496E71956EFA57A23 /* Info.plist.backup */; }; + BC4DC75F4FB823FF40569676 /* NoiseProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95DBE6A48626C5AE287245E /* NoiseProtocolTests.swift */; }; + BCCFEDC1EBE59323C3C470BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A69677D382F1C3D5ED03F7D /* Assets.xcassets */; }; + BCD0EBACD82AF5E55C2CB2B9 /* NostrRelayManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78595178957244CBDF7E79B6 /* NostrRelayManager.swift */; }; + C051EB1A36D52EF14514F392 /* InputValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF5DFD04E7B9B4949DF2420E /* InputValidatorTests.swift */; }; + C06685965753B4F8A3120998 /* UnifiedPeerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D90CBA19E19728938700953D /* UnifiedPeerService.swift */; }; + C0B3B48DD5EA86906AFC58FD /* Packets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5190B5C75639CA5ECFEF16 /* Packets.swift */; }; + C15C22BF8DEF847AC8472F3D /* BLEServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D911BB2E1F2CBF6BCB2D2F /* BLEServiceTests.swift */; }; + C3B1226CD30C87501EF6F12F /* NostrIdentity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8043995007F0D84438EDD9 /* NostrIdentity.swift */; }; + C3CF88649E97134288E0125A /* MeshPeerList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92F634397436B7E8C159B6AF /* MeshPeerList.swift */; }; + C4C2E118D1DAF043E2A06EE7 /* Geohash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28472CF48DAE200A6359E4A6 /* Geohash.swift */; }; + C6FBF0255E9D2DD0402CCE77 /* PeerIDResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 321954679F94D55EBD0979DF /* PeerIDResolver.swift */; }; + C74ABDF6531D66BF2FEEE7FB /* InputValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF5DFD04E7B9B4949DF2420E /* InputValidatorTests.swift */; }; + C79EE1C154773EFF8267B895 /* MessageDeduplicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0BF581F9D98C90EA9867BCF /* MessageDeduplicator.swift */; }; + C887890D4268992A06A391B7 /* PeerDisplayNameResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C08ADEA9AEE89122C19D158 /* PeerDisplayNameResolver.swift */; }; + CB037AFCE7E37E66175D3C0B /* tor-nolzma.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AB4E248FB4EC311F56A1B41 /* tor-nolzma.xcframework */; }; + CCBE0567AEE208B3C23F3294 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 2C82877869239E1E02FF9A88 /* README.md */; }; + CF000339279ADBFC8B817F92 /* MeshPeerList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92F634397436B7E8C159B6AF /* MeshPeerList.swift */; }; + CF6D91BEDA171655613D7463 /* AutocompleteService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C39BB75BC8C2A36039F00613 /* AutocompleteService.swift */; }; + CFB5598BBD80A284B21DBBD8 /* GeohashPeopleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE0E8536824D5431E879831 /* GeohashPeopleList.swift */; }; + D111988977C3BC246AB27FA4 /* SecureLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE7EFB209C86BBD956B749EC /* SecureLogger.swift */; }; + D200A05B319933FFD93B2C73 /* TransportConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B23F0624A8297F993ADF46 /* TransportConfig.swift */; }; + D23DF242816B6E2D2BA2B9D6 /* LocationChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5670E854CD3772439BD68C2C /* LocationChannel.swift */; }; + D3DA203D751932E8D32BCC0F /* LocationChannelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B067FEF619D9D3D14782BA /* LocationChannelsTests.swift */; }; + D450CF41F207BDE1A1AAA56E /* ChatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6B8F7B7D55092C2540A7996 /* ChatViewModel.swift */; }; + D691938B4029A04CC905FDC8 /* NoiseSecurityConsiderations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43B4548DAFC9F7AA8873DA53 /* NoiseSecurityConsiderations.swift */; }; + D727EA273CB214FC32612469 /* MockBluetoothMeshService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27328EE574221395B2B8E87 /* MockBluetoothMeshService.swift */; }; + D7619A7A5EC3914460513841 /* TorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0EDAF53B0CF8AEB6E7D22F4 /* TorManager.swift */; }; + D782AB596DDB5C846554F7C3 /* NostrIdentity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8043995007F0D84438EDD9 /* NostrIdentity.swift */; }; + DC005562A203778E5A58ACA0 /* GeohashBookmarksStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E113B867C7531E4603F7118 /* GeohashBookmarksStoreTests.swift */; }; + DC577E8A96DF704EAC58D7D9 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 41A2626C2788F680C4C2B584 /* libz.tbd */; }; + DD6C921ABE8BB47B131C018B /* GeohashPeopleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE0E8536824D5431E879831 /* GeohashPeopleList.swift */; }; + DFE6C88F3C487BB0FF4A330F /* XChaCha20Poly1305Compat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6B06DDD6D82D60B073A8B7 /* XChaCha20Poly1305Compat.swift */; }; + E1510B9FC6528BB22E21CAC5 /* XChaCha20Poly1305Compat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6B06DDD6D82D60B073A8B7 /* XChaCha20Poly1305Compat.swift */; }; + E2DCF7817344F1CCDB8B7B2F /* SecureIdentityStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC18D910D6FF2E8B1B6C885 /* SecureIdentityStateManager.swift */; }; + E41F5DB8BC5ED0E8F31C0C02 /* BinaryProtocolPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D68C285B6A35B6C74F34529 /* BinaryProtocolPaddingTests.swift */; }; + E4D1CDC8AC341D772142DFFD /* TorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0EDAF53B0CF8AEB6E7D22F4 /* TorManager.swift */; }; + E70F5AF3077C98B2E6A064E6 /* NostrTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B4809E690DE48B9AEE36279 /* NostrTransport.swift */; }; + E89C0DEF56023DA90FC555EB /* tor-nolzma.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8AB4E248FB4EC311F56A1B41 /* tor-nolzma.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + EA763998F218C8E0C8F5679D /* LaunchScreen.storyboard.ios in Resources */ = {isa = PBXBuildFile; fileRef = D112DB3FB47481D2837C763D /* LaunchScreen.storyboard.ios */; }; + EC4532B00C7B9F78B9D488DE /* PeerID.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0569D3728519ED53CD9D7E /* PeerID.swift */; }; + EC5241969D2550B97629EBD0 /* SecureLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE7EFB209C86BBD956B749EC /* SecureLogger.swift */; }; + EC5DD95163C59DF82C7AAE6B /* MessageRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D19E155BC6E68B1F331015 /* MessageRouter.swift */; }; + ED83C7AC1E6BEF15389C0132 /* PrivateChatE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A262EDDC04B7D7B5E31F321 /* PrivateChatE2ETests.swift */; }; + EE8C3ECADAB3083A2687D50B /* NostrProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C272F137CE00FC5A96E0CC06 /* NostrProtocolTests.swift */; }; + EF49C600C1E464710DD6CA29 /* InputValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90CB7A5CD1D1A521CD31F380 /* InputValidator.swift */; }; + EFBF916B28D6CD2E374CA67D /* MessageTextHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B168C6EF326302855D9B71 /* MessageTextHelpers.swift */; }; + F06732B1719EE13C5D09CE77 /* NostrProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E5A9FF4AEA8A923317ED26A /* NostrProtocol.swift */; }; + F0C82B14164A2DD92D3ABD20 /* TorURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761D68EC60DECAEA2513A30 /* TorURLSession.swift */; }; + F44B7D1755FCE00A1D30B399 /* MockBLEService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 568577CDDE5EC8B1A52F8CA0 /* MockBLEService.swift */; }; + F455F011B3B648ADA233F998 /* BinaryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2136C3E22D02D4A8DBE7EAB /* BinaryProtocol.swift */; }; + F54E85DB69E8C7D7039A179C /* tor-nolzma.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AB4E248FB4EC311F56A1B41 /* tor-nolzma.xcframework */; }; + F6D7260109AAA5CAFF9D604F /* GeoRelayDirectory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 259F214DC1197CD705F2FA7B /* GeoRelayDirectory.swift */; }; + F880EF447E80F59506F37B9B /* VerificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3346C98058A0B632BEB1B2 /* VerificationService.swift */; }; + F92C79FB0CB94B39D697178A /* MessageTextHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B168C6EF326302855D9B71 /* MessageTextHelpers.swift */; }; + FB8819B4C84FAFEF5C36B216 /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 136696FC4436A02D98CE6A77 /* KeychainManager.swift */; }; + FBC409E105493C491531B59A /* NostrProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E5A9FF4AEA8A923317ED26A /* NostrProtocol.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 96415D4F989854F908EAD303 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 475D96681D0EA0AE57A4E06E /* Project object */; + proxyType = 1; + remoteGlobalIDString = AF077EA0474EDEDE2C72716C; + remoteInfo = bitchat_iOS; + }; + E35E7AF9854A2E72452DD34F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 475D96681D0EA0AE57A4E06E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 57CA17A36A2532A6CFF367BB; + remoteInfo = bitchatShareExtension; + }; + FF470234EF8C6BB8865B80B5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 475D96681D0EA0AE57A4E06E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0576A29205865664C0937536; + remoteInfo = bitchat_macOS; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + AA02CA2B3081B2935C639418 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + E89C0DEF56023DA90FC555EB /* tor-nolzma.xcframework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + B6C356449BAE4E0F650565D1 /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 17901751FD8010AFC8E750F2 /* bitchatShareExtension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; + C4CD474A599A5F9FCEC800D9 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 4DD1B1593CDE2FFD40546EDD /* tor-nolzma.xcframework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 03C57F452B55FD0FD8F51421 /* bitchatTests_macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = bitchatTests_macOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 04CD884F923001E260886E85 /* CTorHost.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = CTorHost.c; sourceTree = ""; }; + 05BA20BC0F123F1507C5C247 /* IdentityModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityModels.swift; sourceTree = ""; }; + 0B3CC6FA298729906109F61B /* BinaryProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryProtocolTests.swift; sourceTree = ""; }; + 11186E29A064E8D210880E1B /* BitchatPeer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitchatPeer.swift; sourceTree = ""; }; + 136696FC4436A02D98CE6A77 /* KeychainManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainManager.swift; sourceTree = ""; }; + 15B067FEF619D9D3D14782BA /* LocationChannelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationChannelsTests.swift; sourceTree = ""; }; + 1B4809E690DE48B9AEE36279 /* NostrTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrTransport.swift; sourceTree = ""; }; + 1F6B06DDD6D82D60B073A8B7 /* XChaCha20Poly1305Compat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XChaCha20Poly1305Compat.swift; sourceTree = ""; }; + 229F17B68CFF7AB1BC91C847 /* BitchatProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitchatProtocol.swift; sourceTree = ""; }; + 259F214DC1197CD705F2FA7B /* GeoRelayDirectory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoRelayDirectory.swift; sourceTree = ""; }; + 28472CF48DAE200A6359E4A6 /* Geohash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Geohash.swift; sourceTree = ""; }; + 2C82877869239E1E02FF9A88 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 2E346DF8E026FD34EE3DD038 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; }; + 2E5A9FF4AEA8A923317ED26A /* NostrProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrProtocol.swift; sourceTree = ""; }; + 3182D03ECBF0B8F881CA811E /* OSLog+Categories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OSLog+Categories.swift"; sourceTree = ""; }; + 321954679F94D55EBD0979DF /* PeerIDResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerIDResolver.swift; sourceTree = ""; }; + 32F149C43D1915831B60FE09 /* CompressionUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompressionUtil.swift; sourceTree = ""; }; + 3448F84BF86A42A3CC4A9379 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; + 3668EEBB42FD4A24D5D83B7B /* bitchatShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = bitchatShareExtension.entitlements; sourceTree = ""; }; + 38D19E155BC6E68B1F331015 /* MessageRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRouter.swift; sourceTree = ""; }; + 394E8A1AC76EFAE352075BE9 /* NoiseEncryptionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseEncryptionService.swift; sourceTree = ""; }; + 3A556661F74B7D5AE2F0521B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 3A69677D382F1C3D5ED03F7D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 419BFFF209EBA93F410E9E9F /* FavoritesPersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesPersistenceService.swift; sourceTree = ""; }; + 41A2626C2788F680C4C2B584 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 43613045E63D21D429396805 /* NoiseProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseProtocol.swift; sourceTree = ""; }; + 43B4548DAFC9F7AA8873DA53 /* NoiseSecurityConsiderations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseSecurityConsiderations.swift; sourceTree = ""; }; + 4AE0E8536824D5431E879831 /* GeohashPeopleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeohashPeopleList.swift; sourceTree = ""; }; + 4F2899A34E217B55CA551A29 /* FragmentationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FragmentationTests.swift; sourceTree = ""; }; + 527EB217EFDFAD4CF1C91F07 /* bitchat.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = bitchat.entitlements; sourceTree = ""; }; + 5318B743C64628A125261163 /* BinaryEncodingUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryEncodingUtils.swift; sourceTree = ""; }; + 556018DFA405705E5B00E982 /* Transport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transport.swift; sourceTree = ""; }; + 5670E854CD3772439BD68C2C /* LocationChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationChannel.swift; sourceTree = ""; }; + 568577CDDE5EC8B1A52F8CA0 /* MockBLEService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBLEService.swift; sourceTree = ""; }; + 58950BE7879543DBF3F5339A /* GeohashBookmarksStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeohashBookmarksStore.swift; sourceTree = ""; }; + 5BC5AB43F4A8FB62C935CD74 /* IntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = ""; }; + 5C5190B5C75639CA5ECFEF16 /* Packets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Packets.swift; sourceTree = ""; }; + 5F8043995007F0D84438EDD9 /* NostrIdentity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrIdentity.swift; sourceTree = ""; }; + 61F92EBA29C47C0FCC482F1F /* bitchatShareExtension.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = bitchatShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 63B23F0624A8297F993ADF46 /* TransportConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransportConfig.swift; sourceTree = ""; }; + 6CFBF7162BBFF8184561FC64 /* RelayController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayController.swift; sourceTree = ""; }; + 6D69615DF03B207010A964D5 /* TorNotifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorNotifications.swift; sourceTree = ""; }; + 6E113B867C7531E4603F7118 /* GeohashBookmarksStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeohashBookmarksStoreTests.swift; sourceTree = ""; }; + 763E0DBA9492A654FC0CDCB9 /* AppInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppInfoView.swift; sourceTree = ""; }; + 78595178957244CBDF7E79B6 /* NostrRelayManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrRelayManager.swift; sourceTree = ""; }; + 7A9D538710EEF999CC0C2E6F /* VerificationViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationViews.swift; sourceTree = ""; }; + 7D68C285B6A35B6C74F34529 /* BinaryProtocolPaddingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryProtocolPaddingTests.swift; sourceTree = ""; }; + 84D7577ACBFF5D167704FE7E /* TranslationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationService.swift; sourceTree = ""; }; + 8A262EDDC04B7D7B5E31F321 /* PrivateChatE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateChatE2ETests.swift; sourceTree = ""; }; + 8AB4E248FB4EC311F56A1B41 /* tor-nolzma.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = "tor-nolzma.xcframework"; path = "Frameworks/tor-nolzma.xcframework"; sourceTree = ""; }; + 8F3A7C058C2C8E1A06C8CF8B /* bitchat_macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = bitchat_macOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 90CB7A5CD1D1A521CD31F380 /* InputValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputValidator.swift; sourceTree = ""; }; + 9195CDC7EB236AFBC9A4D41A /* FingerprintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FingerprintView.swift; sourceTree = ""; }; + 92B75E0496E71956EFA57A23 /* Info.plist.backup */ = {isa = PBXFileReference; path = Info.plist.backup; sourceTree = ""; }; + 92F634397436B7E8C159B6AF /* MeshPeerList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshPeerList.swift; sourceTree = ""; }; + 935361F3BDD8F966DB207BF7 /* LocationChannelManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationChannelManager.swift; sourceTree = ""; }; + 96B168C6EF326302855D9B71 /* MessageTextHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageTextHelpers.swift; sourceTree = ""; }; + 96D0D41CA19EE5A772AA8434 /* bitchat_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = bitchat_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 9AB6BE4ABD7F5088E9865E56 /* NoiseSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseSession.swift; sourceTree = ""; }; + 9B3346C98058A0B632BEB1B2 /* VerificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationService.swift; sourceTree = ""; }; + 9C08ADEA9AEE89122C19D158 /* PeerDisplayNameResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerDisplayNameResolver.swift; sourceTree = ""; }; + 9E7C4CA419510D61C4FE47B2 /* PrivateChatManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateChatManager.swift; sourceTree = ""; }; + A08E03AA0C63E97C91749AEC /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + A2136C3E22D02D4A8DBE7EAB /* BinaryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryProtocol.swift; sourceTree = ""; }; + A3A1756A6D49A9B037F31A23 /* NostrEmbeddedBitChat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrEmbeddedBitChat.swift; sourceTree = ""; }; + B0BF581F9D98C90EA9867BCF /* MessageDeduplicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageDeduplicator.swift; sourceTree = ""; }; + B1D6A89B36A3D31E590B94E5 /* NoiseHandshakeCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseHandshakeCoordinator.swift; sourceTree = ""; }; + C0DB1DE27F0AAB5092663E8E /* bitchatTests_iOS.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = bitchatTests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + C0EDAF53B0CF8AEB6E7D22F4 /* TorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorManager.swift; sourceTree = ""; }; + C1B378C16594575FCC7F9C75 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; + C272F137CE00FC5A96E0CC06 /* NostrProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrProtocolTests.swift; sourceTree = ""; }; + C27328EE574221395B2B8E87 /* MockBluetoothMeshService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBluetoothMeshService.swift; sourceTree = ""; }; + C39BB75BC8C2A36039F00613 /* AutocompleteService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteService.swift; sourceTree = ""; }; + C9D911BB2E1F2CBF6BCB2D2F /* BLEServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEServiceTests.swift; sourceTree = ""; }; + D112DB3FB47481D2837C763D /* LaunchScreen.storyboard.ios */ = {isa = PBXFileReference; path = LaunchScreen.storyboard.ios; sourceTree = ""; }; + D22BF09A49010947CEFE45E2 /* PublicChatE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicChatE2ETests.swift; sourceTree = ""; }; + D69A18D27F9A565FD6041E12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + D7229DDDE75E1FC21DE3947B /* BLEService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEService.swift; sourceTree = ""; }; + D90CBA19E19728938700953D /* UnifiedPeerService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedPeerService.swift; sourceTree = ""; }; + DB10107B2A552E56B94C0AA4 /* CommandProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandProcessor.swift; sourceTree = ""; }; + DF5DFD04E7B9B4949DF2420E /* InputValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputValidatorTests.swift; sourceTree = ""; }; + E6B8F7B7D55092C2540A7996 /* ChatViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewModel.swift; sourceTree = ""; }; + E95DBE6A48626C5AE287245E /* NoiseProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseProtocolTests.swift; sourceTree = ""; }; + EA706D8E5097785414646A8E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + EBE69984E3D1DC857CCD30A5 /* CommandProcessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandProcessorTests.swift; sourceTree = ""; }; + EC0569D3728519ED53CD9D7E /* PeerID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerID.swift; sourceTree = ""; }; + EE7EFB209C86BBD956B749EC /* SecureLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureLogger.swift; sourceTree = ""; }; + EF625BB3AD919322C01A46B2 /* BitchatApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitchatApp.swift; sourceTree = ""; }; + F27C85DB05C7FB4ADDA3E11D /* LocationChannelsSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationChannelsSheet.swift; sourceTree = ""; }; + F761D68EC60DECAEA2513A30 /* TorURLSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorURLSession.swift; sourceTree = ""; }; + FC75901A0F0073B5BB8356E7 /* TestConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestConstants.swift; sourceTree = ""; }; + FDC18D910D6FF2E8B1B6C885 /* SecureIdentityStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdentityStateManager.swift; sourceTree = ""; }; + FF7AF93D874001FBD94C8306 /* bitchat-macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "bitchat-macOS.entitlements"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 31F6FDADA63050361C14F3A1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3EE336D150427F736F32B56C /* P256K in Frameworks */, + F54E85DB69E8C7D7039A179C /* tor-nolzma.xcframework in Frameworks */, + DC577E8A96DF704EAC58D7D9 /* libz.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B5A5CC493FFB3D8966548140 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 885BBED78092484A5B069461 /* P256K in Frameworks */, + CB037AFCE7E37E66175D3C0B /* tor-nolzma.xcframework in Frameworks */, + 1CB54D76BBB605AD1F46C7D6 /* libz.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0575DCBD15C7C719ADDCB67E /* Models */ = { + isa = PBXGroup; + children = ( + 11186E29A064E8D210880E1B /* BitchatPeer.swift */, + ); + path = Models; + sourceTree = ""; + }; + 18198ED912AAF495D8AF7763 = { + isa = PBXGroup; + children = ( + 2F82C5FC8433F4064F079D1F /* bitchat */, + A2E8C336FA1ADBEC03261DFD /* bitchatShareExtension */, + C3D98EB3E1B455E321F519F4 /* bitchatTests */, + 2DA404873985D7022EA2B1FB /* Frameworks */, + 9F37F9F2C353B58AC809E93B /* Products */, + ); + sourceTree = ""; + }; + 204CC4C7704C7348D456E374 /* TestUtilities */ = { + isa = PBXGroup; + children = ( + FC75901A0F0073B5BB8356E7 /* TestConstants.swift */, + 2E346DF8E026FD34EE3DD038 /* TestHelpers.swift */, + ); + path = TestUtilities; + sourceTree = ""; + }; + 2DA404873985D7022EA2B1FB /* Frameworks */ = { + isa = PBXGroup; + children = ( + 41A2626C2788F680C4C2B584 /* libz.tbd */, + 8AB4E248FB4EC311F56A1B41 /* tor-nolzma.xcframework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 2F82C5FC8433F4064F079D1F /* bitchat */ = { + isa = PBXGroup; + children = ( + 3A69677D382F1C3D5ED03F7D /* Assets.xcassets */, + FF7AF93D874001FBD94C8306 /* bitchat-macOS.entitlements */, + 527EB217EFDFAD4CF1C91F07 /* bitchat.entitlements */, + EF625BB3AD919322C01A46B2 /* BitchatApp.swift */, + EA706D8E5097785414646A8E /* Info.plist */, + 92B75E0496E71956EFA57A23 /* Info.plist.backup */, + D112DB3FB47481D2837C763D /* LaunchScreen.storyboard.ios */, + C845B6F5D25AEEA0B9FE557F /* Identity */, + 0575DCBD15C7C719ADDCB67E /* Models */, + 637EDFDD042BDB5F2569A501 /* Noise */, + E78C7F4B6769C0A72F5DE544 /* Nostr */, + ADD53BCDA233C02E53458926 /* Protocols */, + D98A3186D7E4C72E35BDF7FE /* Services */, + 9A78348821A7D3374607D4E3 /* Utils */, + 45BB7D87CAE42A8C0447D909 /* ViewModels */, + A55126E93155456CAA8D6656 /* Views */, + ); + path = bitchat; + sourceTree = ""; + }; + 45BB7D87CAE42A8C0447D909 /* ViewModels */ = { + isa = PBXGroup; + children = ( + E6B8F7B7D55092C2540A7996 /* ChatViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; + 5B90895AFF0957E08FA3D429 /* Integration */ = { + isa = PBXGroup; + children = ( + 5BC5AB43F4A8FB62C935CD74 /* IntegrationTests.swift */, + ); + path = Integration; + sourceTree = ""; + }; + 637EDFDD042BDB5F2569A501 /* Noise */ = { + isa = PBXGroup; + children = ( + B1D6A89B36A3D31E590B94E5 /* NoiseHandshakeCoordinator.swift */, + 43613045E63D21D429396805 /* NoiseProtocol.swift */, + 43B4548DAFC9F7AA8873DA53 /* NoiseSecurityConsiderations.swift */, + 9AB6BE4ABD7F5088E9865E56 /* NoiseSession.swift */, + ); + path = Noise; + sourceTree = ""; + }; + 674510679B451BEE4812F6C2 /* Fragmentation */ = { + isa = PBXGroup; + children = ( + 4F2899A34E217B55CA551A29 /* FragmentationTests.swift */, + ); + path = Fragmentation; + sourceTree = ""; + }; + 7537A407F8F7A911CC18C857 /* Tor */ = { + isa = PBXGroup; + children = ( + 04CD884F923001E260886E85 /* CTorHost.c */, + C0EDAF53B0CF8AEB6E7D22F4 /* TorManager.swift */, + 6D69615DF03B207010A964D5 /* TorNotifications.swift */, + F761D68EC60DECAEA2513A30 /* TorURLSession.swift */, + ); + path = Tor; + sourceTree = ""; + }; + 84933DAE9D7E5D0155BA7AEA /* Protocol */ = { + isa = PBXGroup; + children = ( + 7D68C285B6A35B6C74F34529 /* BinaryProtocolPaddingTests.swift */, + 0B3CC6FA298729906109F61B /* BinaryProtocolTests.swift */, + ); + path = Protocol; + sourceTree = ""; + }; + 90A4EDA53D5E336C8F8EAFDF /* Utils */ = { + isa = PBXGroup; + children = ( + DF5DFD04E7B9B4949DF2420E /* InputValidatorTests.swift */, + ); + path = Utils; + sourceTree = ""; + }; + 966CD21F221332CF564AC724 /* Mocks */ = { + isa = PBXGroup; + children = ( + 568577CDDE5EC8B1A52F8CA0 /* MockBLEService.swift */, + C27328EE574221395B2B8E87 /* MockBluetoothMeshService.swift */, + ); + path = Mocks; + sourceTree = ""; + }; + 9A78348821A7D3374607D4E3 /* Utils */ = { + isa = PBXGroup; + children = ( + 32F149C43D1915831B60FE09 /* CompressionUtil.swift */, + 90CB7A5CD1D1A521CD31F380 /* InputValidator.swift */, + B0BF581F9D98C90EA9867BCF /* MessageDeduplicator.swift */, + 3182D03ECBF0B8F881CA811E /* OSLog+Categories.swift */, + 9C08ADEA9AEE89122C19D158 /* PeerDisplayNameResolver.swift */, + 321954679F94D55EBD0979DF /* PeerIDResolver.swift */, + EE7EFB209C86BBD956B749EC /* SecureLogger.swift */, + ); + path = Utils; + sourceTree = ""; + }; + 9F37F9F2C353B58AC809E93B /* Products */ = { + isa = PBXGroup; + children = ( + 96D0D41CA19EE5A772AA8434 /* bitchat_iOS.app */, + 8F3A7C058C2C8E1A06C8CF8B /* bitchat_macOS.app */, + 61F92EBA29C47C0FCC482F1F /* bitchatShareExtension.appex */, + C0DB1DE27F0AAB5092663E8E /* bitchatTests_iOS.xctest */, + 03C57F452B55FD0FD8F51421 /* bitchatTests_macOS.xctest */, + ); + name = Products; + sourceTree = ""; + }; + A2E8C336FA1ADBEC03261DFD /* bitchatShareExtension */ = { + isa = PBXGroup; + children = ( + 3668EEBB42FD4A24D5D83B7B /* bitchatShareExtension.entitlements */, + 3A556661F74B7D5AE2F0521B /* Info.plist */, + C1B378C16594575FCC7F9C75 /* ShareViewController.swift */, + ); + path = bitchatShareExtension; + sourceTree = ""; + }; + A55126E93155456CAA8D6656 /* Views */ = { + isa = PBXGroup; + children = ( + 763E0DBA9492A654FC0CDCB9 /* AppInfoView.swift */, + A08E03AA0C63E97C91749AEC /* ContentView.swift */, + 9195CDC7EB236AFBC9A4D41A /* FingerprintView.swift */, + 4AE0E8536824D5431E879831 /* GeohashPeopleList.swift */, + F27C85DB05C7FB4ADDA3E11D /* LocationChannelsSheet.swift */, + 92F634397436B7E8C159B6AF /* MeshPeerList.swift */, + 96B168C6EF326302855D9B71 /* MessageTextHelpers.swift */, + 7A9D538710EEF999CC0C2E6F /* VerificationViews.swift */, + ); + path = Views; + sourceTree = ""; + }; + ADD53BCDA233C02E53458926 /* Protocols */ = { + isa = PBXGroup; + children = ( + 5318B743C64628A125261163 /* BinaryEncodingUtils.swift */, + A2136C3E22D02D4A8DBE7EAB /* BinaryProtocol.swift */, + 229F17B68CFF7AB1BC91C847 /* BitchatProtocol.swift */, + 28472CF48DAE200A6359E4A6 /* Geohash.swift */, + 5670E854CD3772439BD68C2C /* LocationChannel.swift */, + 5C5190B5C75639CA5ECFEF16 /* Packets.swift */, + EC0569D3728519ED53CD9D7E /* PeerID.swift */, + ); + path = Protocols; + sourceTree = ""; + }; + C2F78AB254FDAD5FEDA18B58 /* EndToEnd */ = { + isa = PBXGroup; + children = ( + 8A262EDDC04B7D7B5E31F321 /* PrivateChatE2ETests.swift */, + D22BF09A49010947CEFE45E2 /* PublicChatE2ETests.swift */, + ); + path = EndToEnd; + sourceTree = ""; + }; + C3D98EB3E1B455E321F519F4 /* bitchatTests */ = { + isa = PBXGroup; + children = ( + C9D911BB2E1F2CBF6BCB2D2F /* BLEServiceTests.swift */, + EBE69984E3D1DC857CCD30A5 /* CommandProcessorTests.swift */, + 6E113B867C7531E4603F7118 /* GeohashBookmarksStoreTests.swift */, + D69A18D27F9A565FD6041E12 /* Info.plist */, + 15B067FEF619D9D3D14782BA /* LocationChannelsTests.swift */, + C272F137CE00FC5A96E0CC06 /* NostrProtocolTests.swift */, + 2C82877869239E1E02FF9A88 /* README.md */, + C2F78AB254FDAD5FEDA18B58 /* EndToEnd */, + 674510679B451BEE4812F6C2 /* Fragmentation */, + 5B90895AFF0957E08FA3D429 /* Integration */, + 966CD21F221332CF564AC724 /* Mocks */, + D80E19E04513C0046D611574 /* Noise */, + 84933DAE9D7E5D0155BA7AEA /* Protocol */, + 204CC4C7704C7348D456E374 /* TestUtilities */, + 90A4EDA53D5E336C8F8EAFDF /* Utils */, + ); + path = bitchatTests; + sourceTree = ""; + }; + C845B6F5D25AEEA0B9FE557F /* Identity */ = { + isa = PBXGroup; + children = ( + 05BA20BC0F123F1507C5C247 /* IdentityModels.swift */, + FDC18D910D6FF2E8B1B6C885 /* SecureIdentityStateManager.swift */, + ); + path = Identity; + sourceTree = ""; + }; + D80E19E04513C0046D611574 /* Noise */ = { + isa = PBXGroup; + children = ( + E95DBE6A48626C5AE287245E /* NoiseProtocolTests.swift */, + ); + path = Noise; + sourceTree = ""; + }; + D98A3186D7E4C72E35BDF7FE /* Services */ = { + isa = PBXGroup; + children = ( + C39BB75BC8C2A36039F00613 /* AutocompleteService.swift */, + D7229DDDE75E1FC21DE3947B /* BLEService.swift */, + DB10107B2A552E56B94C0AA4 /* CommandProcessor.swift */, + 419BFFF209EBA93F410E9E9F /* FavoritesPersistenceService.swift */, + 58950BE7879543DBF3F5339A /* GeohashBookmarksStore.swift */, + 136696FC4436A02D98CE6A77 /* KeychainManager.swift */, + 935361F3BDD8F966DB207BF7 /* LocationChannelManager.swift */, + 38D19E155BC6E68B1F331015 /* MessageRouter.swift */, + 394E8A1AC76EFAE352075BE9 /* NoiseEncryptionService.swift */, + 1B4809E690DE48B9AEE36279 /* NostrTransport.swift */, + 3448F84BF86A42A3CC4A9379 /* NotificationService.swift */, + 9E7C4CA419510D61C4FE47B2 /* PrivateChatManager.swift */, + 6CFBF7162BBFF8184561FC64 /* RelayController.swift */, + 84D7577ACBFF5D167704FE7E /* TranslationService.swift */, + 556018DFA405705E5B00E982 /* Transport.swift */, + 63B23F0624A8297F993ADF46 /* TransportConfig.swift */, + D90CBA19E19728938700953D /* UnifiedPeerService.swift */, + 9B3346C98058A0B632BEB1B2 /* VerificationService.swift */, + 7537A407F8F7A911CC18C857 /* Tor */, + ); + path = Services; + sourceTree = ""; + }; + E78C7F4B6769C0A72F5DE544 /* Nostr */ = { + isa = PBXGroup; + children = ( + 259F214DC1197CD705F2FA7B /* GeoRelayDirectory.swift */, + A3A1756A6D49A9B037F31A23 /* NostrEmbeddedBitChat.swift */, + 5F8043995007F0D84438EDD9 /* NostrIdentity.swift */, + 2E5A9FF4AEA8A923317ED26A /* NostrProtocol.swift */, + 78595178957244CBDF7E79B6 /* NostrRelayManager.swift */, + 1F6B06DDD6D82D60B073A8B7 /* XChaCha20Poly1305Compat.swift */, + ); + path = Nostr; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0576A29205865664C0937536 /* bitchat_macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = DA5644925338B8189B035657 /* Build configuration list for PBXNativeTarget "bitchat_macOS" */; + buildPhases = ( + 137ABE739BF20ACDDF8CC605 /* Sources */, + 0214973A876129753D39EB47 /* Resources */, + 31F6FDADA63050361C14F3A1 /* Frameworks */, + AA02CA2B3081B2935C639418 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = bitchat_macOS; + packageProductDependencies = ( + B1D9136AA0083366353BFA2F /* P256K */, + ); + productName = bitchat_macOS; + productReference = 8F3A7C058C2C8E1A06C8CF8B /* bitchat_macOS.app */; + productType = "com.apple.product-type.application"; + }; + 47FF23248747DD7CB666CB91 /* bitchatTests_macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1C27B5BA3DB46DDF0DBFEF62 /* Build configuration list for PBXNativeTarget "bitchatTests_macOS" */; + buildPhases = ( + 5C22AA7B9ACC5A861445C769 /* Sources */, + 7F7221A3304F43E9CF496036 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4AA8605DCAA64A45657EF0CA /* PBXTargetDependency */, + ); + name = bitchatTests_macOS; + packageProductDependencies = ( + ); + productName = bitchatTests_macOS; + productReference = 03C57F452B55FD0FD8F51421 /* bitchatTests_macOS.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 57CA17A36A2532A6CFF367BB /* bitchatShareExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = E4EA6DC648DF55FF84032EB5 /* Build configuration list for PBXNativeTarget "bitchatShareExtension" */; + buildPhases = ( + 0A08E70F08F55FD5BA8C7EF3 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = bitchatShareExtension; + packageProductDependencies = ( + ); + productName = bitchatShareExtension; + productReference = 61F92EBA29C47C0FCC482F1F /* bitchatShareExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; + 6CB97DF2EA57234CB3E563B8 /* bitchatTests_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 38C4AF6313E5037F25CEF30B /* Build configuration list for PBXNativeTarget "bitchatTests_iOS" */; + buildPhases = ( + 865C8403EF02C089369A9FCB /* Sources */, + B42D1108ADC08C2AD4FD6DB5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D8C09F21DB7DC06E8E672C21 /* PBXTargetDependency */, + ); + name = bitchatTests_iOS; + packageProductDependencies = ( + ); + productName = bitchatTests_iOS; + productReference = C0DB1DE27F0AAB5092663E8E /* bitchatTests_iOS.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + AF077EA0474EDEDE2C72716C /* bitchat_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53EADEF7546F94DDF82271B9 /* Build configuration list for PBXNativeTarget "bitchat_iOS" */; + buildPhases = ( + 4E49E34F00154C051AE90FED /* Sources */, + CD6E8F32BC38357473954F97 /* Resources */, + B5A5CC493FFB3D8966548140 /* Frameworks */, + B6C356449BAE4E0F650565D1 /* Embed Foundation Extensions */, + C4CD474A599A5F9FCEC800D9 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 6EB655BA5DB11909C1DEC460 /* PBXTargetDependency */, + ); + name = bitchat_iOS; + packageProductDependencies = ( + 4EB6BA1B8464F1EA38F4E286 /* P256K */, + ); + productName = bitchat_iOS; + productReference = 96D0D41CA19EE5A772AA8434 /* bitchat_iOS.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 475D96681D0EA0AE57A4E06E /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + TargetAttributes = { + 0576A29205865664C0937536 = { + DevelopmentTeam = L3N5LHJD5Y; + ProvisioningStyle = Automatic; + }; + 47FF23248747DD7CB666CB91 = { + DevelopmentTeam = L3N5LHJD5Y; + ProvisioningStyle = Automatic; + }; + 57CA17A36A2532A6CFF367BB = { + DevelopmentTeam = L3N5LHJD5Y; + ProvisioningStyle = Automatic; + }; + 6CB97DF2EA57234CB3E563B8 = { + DevelopmentTeam = L3N5LHJD5Y; + ProvisioningStyle = Automatic; + }; + AF077EA0474EDEDE2C72716C = { + DevelopmentTeam = L3N5LHJD5Y; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 3EA424CBD51200895D361189 /* Build configuration list for PBXProject "bitchat" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = 18198ED912AAF495D8AF7763; + minimizedProjectReferenceProxies = 1; + packageReferences = ( + B8C407587481BBB190741C93 /* XCRemoteSwiftPackageReference "swift-secp256k1" */, + ); + preferredProjectObjectVersion = 77; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 57CA17A36A2532A6CFF367BB /* bitchatShareExtension */, + 6CB97DF2EA57234CB3E563B8 /* bitchatTests_iOS */, + 47FF23248747DD7CB666CB91 /* bitchatTests_macOS */, + AF077EA0474EDEDE2C72716C /* bitchat_iOS */, + 0576A29205865664C0937536 /* bitchat_macOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0214973A876129753D39EB47 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7DD72D928FF9DD3CA81B46B0 /* Assets.xcassets in Resources */, + BC28BE9D0792847556BFC457 /* Info.plist.backup in Resources */, + EA763998F218C8E0C8F5679D /* LaunchScreen.storyboard.ios in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7F7221A3304F43E9CF496036 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CCBE0567AEE208B3C23F3294 /* README.md in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B42D1108ADC08C2AD4FD6DB5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9361A868DCC81BB75DCD8170 /* README.md in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD6E8F32BC38357473954F97 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BCCFEDC1EBE59323C3C470BF /* Assets.xcassets in Resources */, + 064E1DB9D0CAD27E810828DD /* Info.plist.backup in Resources */, + 4DC6562C882AAC5F80DB1246 /* LaunchScreen.storyboard.ios in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0A08E70F08F55FD5BA8C7EF3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9C7D287C8E67AAE576A5ECB7 /* ShareViewController.swift in Sources */, + 415145BEBD6D3E44C79FDB85 /* TransportConfig.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 137ABE739BF20ACDDF8CC605 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AD11E46940D742AEAF547EB2 /* AppInfoView.swift in Sources */, + CF6D91BEDA171655613D7463 /* AutocompleteService.swift in Sources */, + 6775EF2B889D38C1919239C4 /* BLEService.swift in Sources */, + 9B51E9B63A3EA59B1A7874BD /* BinaryEncodingUtils.swift in Sources */, + 4B747085D07A1BCE0F5BA612 /* BinaryProtocol.swift in Sources */, + 6E7761E21C99F28AE2F9BE5F /* BitchatApp.swift in Sources */, + 84E3F9B64FB7FB4A140BD0A8 /* BitchatPeer.swift in Sources */, + 923027D6F2F417AFA2488127 /* BitchatProtocol.swift in Sources */, + A1D2AB3542F0C08C06AAA34B /* CTorHost.c in Sources */, + D450CF41F207BDE1A1AAA56E /* ChatViewModel.swift in Sources */, + B27258BDC071D980D051B65F /* CommandProcessor.swift in Sources */, + B0CA7796B2B2AC2B33F84548 /* CompressionUtil.swift in Sources */, + 92D34E7A07C990C8A815B0CE /* ContentView.swift in Sources */, + 5C93B4FDD0C448C3EDDBF8AE /* FavoritesPersistenceService.swift in Sources */, + 6C63FA98D59854C15C57B3D6 /* FingerprintView.swift in Sources */, + F6D7260109AAA5CAFF9D604F /* GeoRelayDirectory.swift in Sources */, + C4C2E118D1DAF043E2A06EE7 /* Geohash.swift in Sources */, + 8A06DC9D003C4041E1C8884A /* GeohashBookmarksStore.swift in Sources */, + DD6C921ABE8BB47B131C018B /* GeohashPeopleList.swift in Sources */, + 38EDDC049FD56B1BB1F14C91 /* IdentityModels.swift in Sources */, + 7241FFD6CFFB875B864FA223 /* InputValidator.swift in Sources */, + FB8819B4C84FAFEF5C36B216 /* KeychainManager.swift in Sources */, + D23DF242816B6E2D2BA2B9D6 /* LocationChannel.swift in Sources */, + 5A0B730FCFACABE31EC6B402 /* LocationChannelManager.swift in Sources */, + 7935EBDE0EC0E7CB93F14869 /* LocationChannelsSheet.swift in Sources */, + C3CF88649E97134288E0125A /* MeshPeerList.swift in Sources */, + C79EE1C154773EFF8267B895 /* MessageDeduplicator.swift in Sources */, + EC5DD95163C59DF82C7AAE6B /* MessageRouter.swift in Sources */, + F92C79FB0CB94B39D697178A /* MessageTextHelpers.swift in Sources */, + 501BC56B1A08C0327A09AAF1 /* NoiseEncryptionService.swift in Sources */, + AFF33EF44626EF0579D17EB1 /* NoiseHandshakeCoordinator.swift in Sources */, + 8C1AB0F2D48207E0755DA91A /* NoiseProtocol.swift in Sources */, + D691938B4029A04CC905FDC8 /* NoiseSecurityConsiderations.swift in Sources */, + 8A14ADADF5CD7A79919CB655 /* NoiseSession.swift in Sources */, + A92C00F64DBFA588476765A6 /* NostrEmbeddedBitChat.swift in Sources */, + C3B1226CD30C87501EF6F12F /* NostrIdentity.swift in Sources */, + FBC409E105493C491531B59A /* NostrProtocol.swift in Sources */, + 6A85FC357ACD85DBD9020845 /* NostrRelayManager.swift in Sources */, + E70F5AF3077C98B2E6A064E6 /* NostrTransport.swift in Sources */, + 749D8CF8A362B6CD0786782D /* NotificationService.swift in Sources */, + 06882196B7AD8DB19593F712 /* OSLog+Categories.swift in Sources */, + 73F49A7476E8063041EA37E5 /* Packets.swift in Sources */, + 34542C84E4BFA98FC567B533 /* PeerDisplayNameResolver.swift in Sources */, + A1A32ACB18165DD04A5EC540 /* PeerID.swift in Sources */, + C6FBF0255E9D2DD0402CCE77 /* PeerIDResolver.swift in Sources */, + 026A4104B2B4588A88283DB5 /* PrivateChatManager.swift in Sources */, + 07A73CEDC6D73043C6BE4D96 /* RelayController.swift in Sources */, + E2DCF7817344F1CCDB8B7B2F /* SecureIdentityStateManager.swift in Sources */, + D111988977C3BC246AB27FA4 /* SecureLogger.swift in Sources */, + E4D1CDC8AC341D772142DFFD /* TorManager.swift in Sources */, + B313FE7E7263FF9BAD19B60B /* TorNotifications.swift in Sources */, + 8A641F15D219984EA205D715 /* TorURLSession.swift in Sources */, + 1EF5C352D696311955010311 /* TranslationService.swift in Sources */, + 20216EA81EFDC3632F8DB19F /* Transport.swift in Sources */, + D200A05B319933FFD93B2C73 /* TransportConfig.swift in Sources */, + C06685965753B4F8A3120998 /* UnifiedPeerService.swift in Sources */, + F880EF447E80F59506F37B9B /* VerificationService.swift in Sources */, + 9F784B3AEC67201022B0F964 /* VerificationViews.swift in Sources */, + E1510B9FC6528BB22E21CAC5 /* XChaCha20Poly1305Compat.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4E49E34F00154C051AE90FED /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ABAF130D88561F4A646F0430 /* AppInfoView.swift in Sources */, + 34A341E43FC48F4C19B4F805 /* AutocompleteService.swift in Sources */, + 6A30AA6E36BEF48DAD666523 /* BLEService.swift in Sources */, + AFB6AEFCABBE97441CB3102B /* BinaryEncodingUtils.swift in Sources */, + F455F011B3B648ADA233F998 /* BinaryProtocol.swift in Sources */, + 10E68BB889356219189E38EC /* BitchatApp.swift in Sources */, + 84D13329AB7EE1D65A37438A /* BitchatPeer.swift in Sources */, + 6DE056E1EE9850E9FBF50157 /* BitchatProtocol.swift in Sources */, + 79831B2B4C682352326F3FB4 /* CTorHost.c in Sources */, + 7576A357B278E5733E9D9F33 /* ChatViewModel.swift in Sources */, + 429C568B42C2E4460045C795 /* CommandProcessor.swift in Sources */, + 7DCA0DBCB8884E3B31C7BCE3 /* CompressionUtil.swift in Sources */, + 1D9674FA5F998503831DC281 /* ContentView.swift in Sources */, + ACE2ED172C37F01561E50B71 /* FavoritesPersistenceService.swift in Sources */, + 132DF1E24B4E9C7DCDAD4376 /* FingerprintView.swift in Sources */, + 292F514FE3A38B9E6704DBD6 /* GeoRelayDirectory.swift in Sources */, + 08AE06DD4B2F7049047F54E4 /* Geohash.swift in Sources */, + B0DD5633DCD8895ACC289F9B /* GeohashBookmarksStore.swift in Sources */, + CFB5598BBD80A284B21DBBD8 /* GeohashPeopleList.swift in Sources */, + B909706CD38FC56C0C8EB7BF /* IdentityModels.swift in Sources */, + EF49C600C1E464710DD6CA29 /* InputValidator.swift in Sources */, + 8F737CE0435792CC2AD65FCB /* KeychainManager.swift in Sources */, + 7C19D2C9237111A7768E4AD4 /* LocationChannel.swift in Sources */, + 78C3ED98EEF995D463F8179F /* LocationChannelManager.swift in Sources */, + 8373C89F0B3247E875F905FA /* LocationChannelsSheet.swift in Sources */, + CF000339279ADBFC8B817F92 /* MeshPeerList.swift in Sources */, + 44AD79B0EBD4678690E3DEB6 /* MessageDeduplicator.swift in Sources */, + 65A68CE8842A98D9C655E0AA /* MessageRouter.swift in Sources */, + EFBF916B28D6CD2E374CA67D /* MessageTextHelpers.swift in Sources */, + 5EE49E150BBF0488E7473687 /* NoiseEncryptionService.swift in Sources */, + 6D0D4A0B1D8B659DCBAE7C9C /* NoiseHandshakeCoordinator.swift in Sources */, + A7187D48B07C6857DE01D0ED /* NoiseProtocol.swift in Sources */, + 9CCF09F7527EC681A13FC246 /* NoiseSecurityConsiderations.swift in Sources */, + 92D1CF17DF88EA298F6E5E8E /* NoiseSession.swift in Sources */, + 871D35F86A441ECA058880CE /* NostrEmbeddedBitChat.swift in Sources */, + D782AB596DDB5C846554F7C3 /* NostrIdentity.swift in Sources */, + F06732B1719EE13C5D09CE77 /* NostrProtocol.swift in Sources */, + BCD0EBACD82AF5E55C2CB2B9 /* NostrRelayManager.swift in Sources */, + 117F3B1B7D3D372F459DD998 /* NostrTransport.swift in Sources */, + 61C81ED5F679D5E973EE0C07 /* NotificationService.swift in Sources */, + 442FEE403846A040CF306CF9 /* OSLog+Categories.swift in Sources */, + C0B3B48DD5EA86906AFC58FD /* Packets.swift in Sources */, + C887890D4268992A06A391B7 /* PeerDisplayNameResolver.swift in Sources */, + EC4532B00C7B9F78B9D488DE /* PeerID.swift in Sources */, + 33F91269305DEBFBC87489C9 /* PeerIDResolver.swift in Sources */, + 85A86060AD95600D56FDF5BC /* PrivateChatManager.swift in Sources */, + 2E02905CBE350A2A168362E1 /* RelayController.swift in Sources */, + 68C4BE564735F6E7915274A2 /* SecureIdentityStateManager.swift in Sources */, + EC5241969D2550B97629EBD0 /* SecureLogger.swift in Sources */, + D7619A7A5EC3914460513841 /* TorManager.swift in Sources */, + B8C285C2890920924A54FCBE /* TorNotifications.swift in Sources */, + F0C82B14164A2DD92D3ABD20 /* TorURLSession.swift in Sources */, + B2ED9C2A5CDAFADC48237072 /* TranslationService.swift in Sources */, + 778592DC0729708A653D6B9A /* Transport.swift in Sources */, + 6DE24385FD4339F392927D0E /* TransportConfig.swift in Sources */, + 438E81C9D07DABC9D6B86AD7 /* UnifiedPeerService.swift in Sources */, + 3EB848E57515ACA257FA05BC /* VerificationService.swift in Sources */, + A0F4471D8974C5D3A317F6EC /* VerificationViews.swift in Sources */, + DFE6C88F3C487BB0FF4A330F /* XChaCha20Poly1305Compat.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5C22AA7B9ACC5A861445C769 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 465F776816537C720DEB8600 /* BLEServiceTests.swift in Sources */, + 3A335CC28AE409554184936F /* BinaryProtocolPaddingTests.swift in Sources */, + AA6E067DB034FC0FA23C28A9 /* BinaryProtocolTests.swift in Sources */, + 1C6705FCCFBFD24E74C73E7C /* CommandProcessorTests.swift in Sources */, + 1BD3295CA4D57C93C0A6522C /* FragmentationTests.swift in Sources */, + DC005562A203778E5A58ACA0 /* GeohashBookmarksStoreTests.swift in Sources */, + C051EB1A36D52EF14514F392 /* InputValidatorTests.swift in Sources */, + 8F282E9CCA5AE1ECC001D2E4 /* IntegrationTests.swift in Sources */, + 4F2F1893E90C1B13D388CEA9 /* LocationChannelsTests.swift in Sources */, + 3EA8279F12C05DC2CE42AF05 /* MockBLEService.swift in Sources */, + D727EA273CB214FC32612469 /* MockBluetoothMeshService.swift in Sources */, + 765254F56997F01054699AC0 /* NoiseProtocolTests.swift in Sources */, + 968181D255CA7A804340B4DA /* NostrProtocolTests.swift in Sources */, + ED83C7AC1E6BEF15389C0132 /* PrivateChatE2ETests.swift in Sources */, + A0A1C26EFBFDD5B8EFEEDE57 /* PublicChatE2ETests.swift in Sources */, + 2EFCCAA297B16FA2B56747C7 /* TestConstants.swift in Sources */, + B45AD5BF95220A0289216D32 /* TestHelpers.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 865C8403EF02C089369A9FCB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C15C22BF8DEF847AC8472F3D /* BLEServiceTests.swift in Sources */, + E41F5DB8BC5ED0E8F31C0C02 /* BinaryProtocolPaddingTests.swift in Sources */, + 0B6F25559A21F8C69C8357C6 /* BinaryProtocolTests.swift in Sources */, + B416A6EFCC86F4FC08A73898 /* CommandProcessorTests.swift in Sources */, + 03B8B21F0F40DD0BF98D397B /* FragmentationTests.swift in Sources */, + 39E236E0CA2C6F25D6E7E773 /* GeohashBookmarksStoreTests.swift in Sources */, + C74ABDF6531D66BF2FEEE7FB /* InputValidatorTests.swift in Sources */, + 686441ABC2AF83EE98E6ECF2 /* IntegrationTests.swift in Sources */, + D3DA203D751932E8D32BCC0F /* LocationChannelsTests.swift in Sources */, + F44B7D1755FCE00A1D30B399 /* MockBLEService.swift in Sources */, + 8851F08D88C5B1DE7B9F55C6 /* MockBluetoothMeshService.swift in Sources */, + BC4DC75F4FB823FF40569676 /* NoiseProtocolTests.swift in Sources */, + EE8C3ECADAB3083A2687D50B /* NostrProtocolTests.swift in Sources */, + 0AE840940F21AFC07C226636 /* PrivateChatE2ETests.swift in Sources */, + 8CE446C9364F54DF89E7A364 /* PublicChatE2ETests.swift in Sources */, + 8D0196EAEE56973679F6A655 /* TestConstants.swift in Sources */, + 37DDF3D09E2BAB92A5A8A9C1 /* TestHelpers.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 4AA8605DCAA64A45657EF0CA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0576A29205865664C0937536 /* bitchat_macOS */; + targetProxy = FF470234EF8C6BB8865B80B5 /* PBXContainerItemProxy */; + }; + 6EB655BA5DB11909C1DEC460 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 57CA17A36A2532A6CFF367BB /* bitchatShareExtension */; + targetProxy = E35E7AF9854A2E72452DD34F /* PBXContainerItemProxy */; + }; + D8C09F21DB7DC06E8E672C21 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = AF077EA0474EDEDE2C72716C /* bitchat_iOS */; + targetProxy = 96415D4F989854F908EAD303 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 077A5203074247CF8F766E2F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + INFOPLIST_FILE = bitchatTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.tests; + SDKROOT = iphoneos; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bitchat.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bitchat"; + }; + name = Debug; + }; + 0DACAA261446D178EDD30ECA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + INFOPLIST_FILE = bitchatTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.tests; + SDKROOT = iphoneos; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bitchat.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bitchat"; + }; + name = Release; + }; + 147FDAE548082D5B921C6F0B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + INFOPLIST_FILE = bitchatTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.0; + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.tests; + SDKROOT = macosx; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bitchat.app/Contents/MacOS/bitchat"; + }; + name = Release; + }; + 3DCF45111852FB2AEBE05E31 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; + CODE_SIGN_ENTITLEMENTS = bitchatShareExtension/bitchatShareExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + INFOPLIST_FILE = bitchatShareExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.ShareExtension; + SDKROOT = iphoneos; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 702E7395723CADA4B830F4A9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_ENTITLEMENTS = bitchat/bitchat.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"Frameworks\"", + ); + INFOPLIST_FILE = bitchat/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; + PRODUCT_NAME = bitchat; + SDKROOT = iphoneos; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 7FA2BADBF3B325125030CAB1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + INFOPLIST_FILE = bitchatTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.0; + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.tests; + SDKROOT = macosx; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bitchat.app/Contents/MacOS/bitchat"; + }; + name = Debug; + }; + B36671AEACCBF92BE10852E9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_ENTITLEMENTS = bitchat/bitchat.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"Frameworks\"", + ); + INFOPLIST_FILE = bitchat/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; + PRODUCT_NAME = bitchat; + SDKROOT = iphoneos; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + BB044400A0F06B93F22D0D55 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_ENTITLEMENTS = "bitchat/bitchat-macOS.entitlements"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + ENABLE_PREVIEWS = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"Frameworks\"", + ); + INFOPLIST_FILE = bitchat/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.0; + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; + PRODUCT_NAME = bitchat; + SDKROOT = macosx; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + BF0D85727BCB6E346962F419 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.0.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + CC79F65842D42034ACEE79B7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_ENTITLEMENTS = "bitchat/bitchat-macOS.entitlements"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + ENABLE_PREVIEWS = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"Frameworks\"", + ); + INFOPLIST_FILE = bitchat/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.0; + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; + PRODUCT_NAME = bitchat; + SDKROOT = macosx; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + D8C5BF109BB2630752185FA0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "DEBUG=1", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.0.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + DAC5E82049F8A97360BE63D6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGNING_ALLOWED = YES; + CODE_SIGNING_REQUIRED = YES; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; + CODE_SIGN_ENTITLEMENTS = bitchatShareExtension/bitchatShareExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = L3N5LHJD5Y; + INFOPLIST_FILE = bitchatShareExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.ShareExtension; + SDKROOT = iphoneos; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1C27B5BA3DB46DDF0DBFEF62 /* Build configuration list for PBXNativeTarget "bitchatTests_macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7FA2BADBF3B325125030CAB1 /* Debug */, + 147FDAE548082D5B921C6F0B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 38C4AF6313E5037F25CEF30B /* Build configuration list for PBXNativeTarget "bitchatTests_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 077A5203074247CF8F766E2F /* Debug */, + 0DACAA261446D178EDD30ECA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 3EA424CBD51200895D361189 /* Build configuration list for PBXProject "bitchat" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D8C5BF109BB2630752185FA0 /* Debug */, + BF0D85727BCB6E346962F419 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 53EADEF7546F94DDF82271B9 /* Build configuration list for PBXNativeTarget "bitchat_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 702E7395723CADA4B830F4A9 /* Debug */, + B36671AEACCBF92BE10852E9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + DA5644925338B8189B035657 /* Build configuration list for PBXNativeTarget "bitchat_macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CC79F65842D42034ACEE79B7 /* Debug */, + BB044400A0F06B93F22D0D55 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + E4EA6DC648DF55FF84032EB5 /* Build configuration list for PBXNativeTarget "bitchatShareExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DAC5E82049F8A97360BE63D6 /* Debug */, + 3DCF45111852FB2AEBE05E31 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + B8C407587481BBB190741C93 /* XCRemoteSwiftPackageReference "swift-secp256k1" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/21-DOT-DEV/swift-secp256k1"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.21.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 4EB6BA1B8464F1EA38F4E286 /* P256K */ = { + isa = XCSwiftPackageProductDependency; + package = B8C407587481BBB190741C93 /* XCRemoteSwiftPackageReference "swift-secp256k1" */; + productName = P256K; + }; + B1D9136AA0083366353BFA2F /* P256K */ = { + isa = XCSwiftPackageProductDependency; + package = B8C407587481BBB190741C93 /* XCRemoteSwiftPackageReference "swift-secp256k1" */; + productName = P256K; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 475D96681D0EA0AE57A4E06E /* Project object */; +} diff --git a/bitchat/Info.plist.backup b/bitchat/Info.plist.backup new file mode 100644 index 000000000..5d0a9984c --- /dev/null +++ b/bitchat/Info.plist.backup @@ -0,0 +1,56 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + bitchat + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleURLTypes + + + CFBundleURLSchemes + + bitchat + + + + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSBluetoothAlwaysUsageDescription + bitchat uses Bluetooth to create a secure mesh network for chatting with nearby users. + NSBluetoothPeripheralUsageDescription + bitchat uses Bluetooth to discover and connect with other bitchat users nearby. + NSCameraUsageDescription + bitchat uses the camera to scan QR codes to verify peers. + NSLocationWhenInUseUsageDescription + bitchat uses your approximate location to compute local geohash channels for optional public chats. Exact GPS is never shared. + UIBackgroundModes + + bluetooth-central + bluetooth-peripheral + + UILaunchStoryboardName + LaunchScreen + UIRequiresFullScreen + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/bitchat/LaunchScreen.storyboard b/bitchat/LaunchScreen.storyboard new file mode 100644 index 000000000..7d2b247a4 --- /dev/null +++ b/bitchat/LaunchScreen.storyboard @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bitchat/Services/MLXTranslationService.swift b/bitchat/Services/MLXTranslationService.swift index 3361ee7fa..679ce489a 100644 --- a/bitchat/Services/MLXTranslationService.swift +++ b/bitchat/Services/MLXTranslationService.swift @@ -94,7 +94,7 @@ class MLXTranslationService { let messages = [["role": "user", "content": prompt]] let result = try await container.perform { context in - let userInput = MLXLMCommon.UserInput(messages: messages) + let userInput = MLXLMCommon.UserInput(messages: messages) let lmInput = try await context.processor.prepare(input: userInput) var tokenCount = 0 diff --git a/bitchat/bitchat-macOS.entitlements b/bitchat/bitchat-macOS.entitlements index a3f413dfd..202564c02 100644 --- a/bitchat/bitchat-macOS.entitlements +++ b/bitchat/bitchat-macOS.entitlements @@ -5,16 +5,14 @@ com.apple.security.app-sandbox com.apple.security.application-groups - - group.chat.bitchat - + com.apple.security.device.bluetooth - com.apple.security.personal-information.location - com.apple.security.network.client com.apple.security.network.server + com.apple.security.personal-information.location + diff --git a/bitchat/bitchat.entitlements b/bitchat/bitchat.entitlements index 610b08cbb..4c00bc8ba 100644 --- a/bitchat/bitchat.entitlements +++ b/bitchat/bitchat.entitlements @@ -5,10 +5,8 @@ com.apple.security.app-sandbox com.apple.security.application-groups - - group.chat.bitchat - + com.apple.security.device.bluetooth - \ No newline at end of file + diff --git a/bitchatShareExtension/bitchatShareExtension.entitlements b/bitchatShareExtension/bitchatShareExtension.entitlements index 805666161..0ddcbeb1b 100644 --- a/bitchatShareExtension/bitchatShareExtension.entitlements +++ b/bitchatShareExtension/bitchatShareExtension.entitlements @@ -5,8 +5,6 @@ com.apple.security.app-sandbox com.apple.security.application-groups - - group.chat.bitchat - + - \ No newline at end of file + diff --git a/project.yml.backup b/project.yml.backup new file mode 100644 index 000000000..90e9e4ae7 --- /dev/null +++ b/project.yml.backup @@ -0,0 +1,236 @@ +name: bitchat +options: + bundleIdPrefix: chat.bitchat + deploymentTarget: + iOS: 16.0 + macOS: 13.0 + createIntermediateGroups: true + +settings: + MARKETING_VERSION: 1.0.0 + CURRENT_PROJECT_VERSION: 1 + +packages: + P256K: + url: https://github.com/21-DOT-DEV/swift-secp256k1 + majorVersion: 0.21.1 + +targets: + bitchat_iOS: + type: application + platform: iOS + sources: + - bitchat + resources: + - bitchat/Assets.xcassets + - bitchat/LaunchScreen.storyboard + info: + path: bitchat/Info.plist + properties: + CFBundleDisplayName: bitchat + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + NSBluetoothAlwaysUsageDescription: bitchat uses Bluetooth to create a secure mesh network for chatting with nearby users. + NSBluetoothPeripheralUsageDescription: bitchat uses Bluetooth to discover and connect with other bitchat users nearby. + NSCameraUsageDescription: bitchat uses the camera to scan QR codes to verify peers. + NSLocationWhenInUseUsageDescription: bitchat uses your approximate location to compute local geohash channels for optional public chats. Exact GPS is never shared. + UIBackgroundModes: + - bluetooth-central + - bluetooth-peripheral + UILaunchStoryboardName: LaunchScreen + UISupportedInterfaceOrientations: + - UIInterfaceOrientationPortrait + UISupportedInterfaceOrientations~ipad: + - UIInterfaceOrientationPortrait + - UIInterfaceOrientationPortraitUpsideDown + - UIInterfaceOrientationLandscapeLeft + - UIInterfaceOrientationLandscapeRight + UIRequiresFullScreen: false + CFBundleURLTypes: + - CFBundleURLSchemes: + - bitchat + # xcodegen quirk: include some macOS properties in iOS target + LSMinimumSystemVersion: $(MACOSX_DEPLOYMENT_TARGET) + settings: + PRODUCT_BUNDLE_IDENTIFIER: chat.bitchat + PRODUCT_NAME: bitchat + INFOPLIST_FILE: bitchat/Info.plist + ENABLE_PREVIEWS: YES + SWIFT_VERSION: 5.0 + IPHONEOS_DEPLOYMENT_TARGET: 16.0 + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: YES + CODE_SIGN_STYLE: Automatic + CODE_SIGNING_REQUIRED: YES + CODE_SIGNING_ALLOWED: YES + DEVELOPMENT_TEAM: L3N5LHJD5Y + ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS: YES + CODE_SIGN_ENTITLEMENTS: bitchat/bitchat.entitlements + dependencies: + - target: bitchatShareExtension + embed: true + - package: P256K + - framework: Frameworks/tor-nolzma.xcframework + embed: true + codeSign: true + - sdk: libz.tbd + + bitchat_macOS: + type: application + platform: macOS + sources: + - bitchat + resources: + - bitchat/Assets.xcassets + info: + path: bitchat/Info.plist + properties: + CFBundleDisplayName: bitchat + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + LSMinimumSystemVersion: $(MACOSX_DEPLOYMENT_TARGET) + NSBluetoothAlwaysUsageDescription: bitchat uses Bluetooth to create a secure mesh network for chatting with nearby users. + NSBluetoothPeripheralUsageDescription: bitchat uses Bluetooth to discover and connect with other bitchat users nearby. + NSCameraUsageDescription: bitchat uses the camera to scan QR codes to verify peers. + NSLocationWhenInUseUsageDescription: bitchat uses your approximate location to compute local geohash channels for optional public chats. Exact GPS is never shared. + CFBundleURLTypes: + - CFBundleURLSchemes: + - bitchat + # xcodegen quirk: include some iOS properties in macOS target + UIBackgroundModes: + - bluetooth-central + - bluetooth-peripheral + UILaunchStoryboardName: LaunchScreen + UISupportedInterfaceOrientations: + - UIInterfaceOrientationPortrait + UIRequiresFullScreen: true + settings: + PRODUCT_BUNDLE_IDENTIFIER: chat.bitchat + PRODUCT_NAME: bitchat + INFOPLIST_FILE: bitchat/Info.plist + ENABLE_PREVIEWS: NO + SWIFT_VERSION: 5.0 + MACOSX_DEPLOYMENT_TARGET: 13.0 + CODE_SIGN_STYLE: Automatic + CODE_SIGNING_REQUIRED: YES + CODE_SIGNING_ALLOWED: YES + DEVELOPMENT_TEAM: L3N5LHJD5Y + ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS: YES + CODE_SIGN_ENTITLEMENTS: bitchat/bitchat-macOS.entitlements + dependencies: + - package: P256K + - framework: Frameworks/tor-nolzma.xcframework + embed: true + codeSign: true + - sdk: libz.tbd + + bitchatShareExtension: + type: app-extension + platform: iOS + sources: + - bitchatShareExtension + - bitchat/Services/TransportConfig.swift + info: + path: bitchatShareExtension/Info.plist + properties: + CFBundleDisplayName: bitchat + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + NSExtension: + NSExtensionPointIdentifier: com.apple.share-services + NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).ShareViewController + NSExtensionAttributes: + NSExtensionActivationRule: + NSExtensionActivationSupportsText: true + NSExtensionActivationSupportsWebURLWithMaxCount: 1 + NSExtensionActivationSupportsImageWithMaxCount: 1 + settings: + PRODUCT_BUNDLE_IDENTIFIER: chat.bitchat.ShareExtension + INFOPLIST_FILE: bitchatShareExtension/Info.plist + SWIFT_VERSION: 5.0 + IPHONEOS_DEPLOYMENT_TARGET: 16.0 + CODE_SIGN_STYLE: Automatic + CODE_SIGNING_REQUIRED: YES + CODE_SIGNING_ALLOWED: YES + DEVELOPMENT_TEAM: L3N5LHJD5Y + CODE_SIGN_ENTITLEMENTS: bitchatShareExtension/bitchatShareExtension.entitlements + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION: YES + + bitchatTests_iOS: + type: bundle.unit-test + platform: iOS + sources: + - bitchatTests + dependencies: + - target: bitchat_iOS + settings: + PRODUCT_BUNDLE_IDENTIFIER: chat.bitchat.tests + INFOPLIST_FILE: bitchatTests/Info.plist + SWIFT_VERSION: 5.0 + IPHONEOS_DEPLOYMENT_TARGET: 16.0 + TEST_HOST: $(BUILT_PRODUCTS_DIR)/bitchat.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bitchat + BUNDLE_LOADER: $(TEST_HOST) + CODE_SIGN_STYLE: Automatic + CODE_SIGNING_REQUIRED: YES + CODE_SIGNING_ALLOWED: YES + DEVELOPMENT_TEAM: L3N5LHJD5Y + + bitchatTests_macOS: + type: bundle.unit-test + platform: macOS + sources: + - bitchatTests + dependencies: + - target: bitchat_macOS + settings: + PRODUCT_BUNDLE_IDENTIFIER: chat.bitchat.tests + INFOPLIST_FILE: bitchatTests/Info.plist + SWIFT_VERSION: 5.0 + MACOSX_DEPLOYMENT_TARGET: 13.0 + TEST_HOST: $(BUILT_PRODUCTS_DIR)/bitchat.app/Contents/MacOS/bitchat + BUNDLE_LOADER: $(TEST_HOST) + CODE_SIGN_STYLE: Automatic + CODE_SIGNING_REQUIRED: YES + CODE_SIGNING_ALLOWED: YES + DEVELOPMENT_TEAM: L3N5LHJD5Y + +schemes: + bitchat (iOS): + build: + targets: + bitchat_iOS: all + bitchatShareExtension: all + run: + config: Debug + executable: bitchat_iOS + test: + config: Debug + targets: + - bitchatTests_iOS + profile: + config: Release + executable: bitchat_iOS + analyze: + config: Debug + archive: + config: Release + + bitchat (macOS): + build: + targets: + bitchat_macOS: all + run: + config: Debug + executable: bitchat_macOS + test: + config: Debug + targets: + - bitchatTests_macOS + profile: + config: Release + executable: bitchat_macOS + analyze: + config: Debug + archive: + config: Release