diff --git a/Luma.xcodeproj/project.pbxproj b/Luma.xcodeproj/project.pbxproj index 2388281..ec6446d 100644 --- a/Luma.xcodeproj/project.pbxproj +++ b/Luma.xcodeproj/project.pbxproj @@ -344,7 +344,7 @@ 6079CE75BAB995515A8D5460 /* CallSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSnapshot.swift; sourceTree = ""; }; 60A97545E6E481D45E0BB20F /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = ""; }; 61380B78824FDB98A933C7E9 /* ArchiveSyncRecoveryPolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveSyncRecoveryPolicyTests.swift; sourceTree = ""; }; - 6317FAA29F22A3EA8450208F /* LumaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LumaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 6317FAA29F22A3EA8450208F /* LumaTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = LumaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63E4D099BDCB2311ADFE39E6 /* CallHistorySync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallHistorySync.swift; sourceTree = ""; }; 6773F87EE60F91BBDCA4B1F5 /* GroupConversationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupConversationTests.swift; sourceTree = ""; }; 69F4FFBFD65C218FF6505844 /* SaslFailureMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaslFailureMessage.swift; sourceTree = ""; }; @@ -417,12 +417,12 @@ D8C81B9255E9886FB86E0785 /* InlineVideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineVideoPlayer.swift; sourceTree = ""; }; D9BBE412EAF54DFE968B2E54 /* ArchiveSyncCheckpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveSyncCheckpoint.swift; sourceTree = ""; }; D9FCE089ABBF05EF9F55D451 /* VideoNoteRecordingLifecycleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoNoteRecordingLifecycleTests.swift; sourceTree = ""; }; - DF8C531E464C9C4EDE2648C6 /* Luma.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Luma.app; sourceTree = BUILT_PRODUCTS_DIR; }; + DF8C531E464C9C4EDE2648C6 /* Luma.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = Luma.app; sourceTree = BUILT_PRODUCTS_DIR; }; E619B2C85B0DD2E80653D6D3 /* VideoNoteRecordingCompletionPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoNoteRecordingCompletionPolicy.swift; sourceTree = ""; }; E6A5C32B4DACD56DA733A0DB /* ServerInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerInformation.swift; sourceTree = ""; }; E9F226A1F8D82B39630F9CEB /* LumaRoomStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LumaRoomStore.swift; sourceTree = ""; }; EA1D94FE541121DAE9DCE3B0 /* LegacyArchiveImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyArchiveImporter.swift; sourceTree = ""; }; - EA54340DD785335237158BEF /* Luma.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Luma.app; sourceTree = BUILT_PRODUCTS_DIR; }; + EA54340DD785335237158BEF /* LumaMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LumaMac.app; sourceTree = BUILT_PRODUCTS_DIR; }; F0A35C9A7B52458996513382 /* WatchVoiceRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchVoiceRecorder.swift; sourceTree = ""; }; F207C1B20DE3780F1754F81D /* ConnectionBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionBanner.swift; sourceTree = ""; }; F26F91180E43DE9C135B68C1 /* EmojiCatalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCatalog.swift; sourceTree = ""; }; @@ -683,7 +683,7 @@ isa = PBXGroup; children = ( DF8C531E464C9C4EDE2648C6 /* Luma.app */, - EA54340DD785335237158BEF /* Luma.app */, + EA54340DD785335237158BEF /* LumaMac.app */, 6317FAA29F22A3EA8450208F /* LumaTests.xctest */, 19D4E9404712E8643E31CB93 /* LumaWatch.app */, ); @@ -767,7 +767,7 @@ 2A745A82DD6F34F0CB46B52B /* WebRTC */, ); productName = LumaMac; - productReference = EA54340DD785335237158BEF /* Luma.app */; + productReference = EA54340DD785335237158BEF /* LumaMac.app */; productType = "com.apple.product-type.application"; }; BAB78463D7DE07A8F7B3D27D /* LumaWatch */ = { @@ -813,7 +813,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 2660; + LastUpgradeCheck = 1600; TargetAttributes = { 0565F6C7DA26F0482928704E = { DevelopmentTeam = K3AS449A74; @@ -1169,7 +1169,6 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_ENTITLEMENTS = Config/LumaMac.entitlements; COMBINE_HIDPI_IMAGES = YES; - DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = K3AS449A74; INFOPLIST_FILE = "Config/LumaMac-Info.plist"; INFOPLIST_KEY_CFBundleIconName = AppIcon; @@ -1192,7 +1191,6 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_ENTITLEMENTS = Config/LumaMac.entitlements; COMBINE_HIDPI_IMAGES = YES; - DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = K3AS449A74; INFOPLIST_FILE = "Config/LumaMac-Info.plist"; INFOPLIST_KEY_CFBundleIconName = AppIcon; @@ -1290,7 +1288,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -1324,7 +1321,6 @@ COMPANION_BUNDLE_IDENTIFIER = app.luma.chat; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 31; - DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -1348,7 +1344,6 @@ MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; - STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.9; @@ -1378,7 +1373,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -1412,7 +1406,6 @@ COMPANION_BUNDLE_IDENTIFIER = app.luma.chat; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 31; - DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -1429,7 +1422,6 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; - STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.9; diff --git a/Luma.xcodeproj/xcshareddata/xcschemes/Luma.xcscheme b/Luma.xcodeproj/xcshareddata/xcschemes/Luma.xcscheme index c16868a..b7f0e83 100644 --- a/Luma.xcodeproj/xcshareddata/xcschemes/Luma.xcscheme +++ b/Luma.xcodeproj/xcshareddata/xcschemes/Luma.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1600" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + + + CGFloat { guard isHorizontal(translation) else { return 0 } - let distance = min(abs(translation.width) * 0.72, maximumOffset) + let width = abs(translation.width) + guard width >= activationDistance else { return 0 } + let distance = min((width - activationDistance) * 0.72 + 12, maximumOffset) return translation.width < 0 ? -distance : distance } diff --git a/Sources/Shared/UI/Components/MessageBubble.swift b/Sources/Shared/UI/Components/MessageBubble.swift index e2ed8f6..db33f8c 100644 --- a/Sources/Shared/UI/Components/MessageBubble.swift +++ b/Sources/Shared/UI/Components/MessageBubble.swift @@ -177,9 +177,16 @@ struct MessageBubble: View { DragGesture(minimumDistance: 20) .onChanged { value in let offset = MessageReplySwipePolicy.offset(for: value.translation) - guard offset != 0 || replySwipeOffset != 0 else { - // A vertical timeline pan must not publish per-cell state - // changes or compete with UIScrollView's own recognizer. + guard offset != 0 else { + // Vertical (or not clearly horizontal) movement: snap the + // indicator back and never publish per-cell state changes + // during an ordinary timeline scroll. + if replySwipeOffset != 0 || replySwipeArmed { + withAnimation(.spring(response: 0.24, dampingFraction: 0.82)) { + replySwipeOffset = 0 + } + replySwipeArmed = false + } return } replySwipeOffset = offset diff --git a/Tests/MessageReplySwipeTests.swift b/Tests/MessageReplySwipeTests.swift index 516aa0a..3707548 100644 --- a/Tests/MessageReplySwipeTests.swift +++ b/Tests/MessageReplySwipeTests.swift @@ -46,6 +46,30 @@ final class MessageReplySwipeTests: XCTestCase { )) } + func testDiagonalScrollAtOldThresholdDoesNotReply() { + // width/height ≈ 1.5 passed the old 1.4 dominance and moved bubbles + // during scrolling; the stricter policy must stay silent. + XCTAssertFalse(MessageReplySwipePolicy.shouldReply( + translation: CGSize(width: 60, height: 40), + predictedEndTranslation: CGSize(width: 60, height: 40) + )) + XCTAssertEqual( + MessageReplySwipePolicy.offset(for: CGSize(width: 60, height: 40)), + 0 + ) + } + + func testIndicatorStaysHiddenUntilActivationDistance() { + XCTAssertEqual( + MessageReplySwipePolicy.offset(for: CGSize(width: 20, height: 0)), + 0 + ) + XCTAssertGreaterThan( + MessageReplySwipePolicy.offset(for: CGSize(width: 24, height: 0)), + 0 + ) + } + func testVisualOffsetIsCapped() { XCTAssertEqual( MessageReplySwipePolicy.offset(for: CGSize(width: 500, height: 0)),