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 c3e4b26cb..ef1f423b2 100644
--- a/Package.swift
+++ b/Package.swift
@@ -16,12 +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-examples/", branch: "main"),
],
targets: [
.executableTarget(
name: "bitchat",
dependencies: [
- .product(name: "P256K", package: "swift-secp256k1")
+ .product(name: "P256K", package: "swift-secp256k1"),
+ .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/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/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/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..679ce489a
--- /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
+ }
+ }
+}
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