tame the reply swipe so vertical scrolling stays clean
- Raise the swipe dominance threshold to 2.0 and add a 24pt activation distance so diagonal timeline scrolls never move bubbles or fire haptics, and snap the indicator back when a gesture turns vertical mid-drag. - Cover the stricter thresholds in MessageReplySwipeTests.
This commit is contained in:
1 parent
1a26651daa
commit
0ef77f7f6a
7 files changed
+61
-25
No files matched your search
@@ -344,7 +344,7 @@
|
|||||||
6079CE75BAB995515A8D5460 /* CallSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSnapshot.swift; sourceTree = "<group>"; };
|
6079CE75BAB995515A8D5460 /* CallSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSnapshot.swift; sourceTree = "<group>"; };
|
||||||
60A97545E6E481D45E0BB20F /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = "<group>"; };
|
60A97545E6E481D45E0BB20F /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = "<group>"; };
|
||||||
61380B78824FDB98A933C7E9 /* ArchiveSyncRecoveryPolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveSyncRecoveryPolicyTests.swift; sourceTree = "<group>"; };
|
61380B78824FDB98A933C7E9 /* ArchiveSyncRecoveryPolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveSyncRecoveryPolicyTests.swift; sourceTree = "<group>"; };
|
||||||
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 = "<group>"; };
|
63E4D099BDCB2311ADFE39E6 /* CallHistorySync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallHistorySync.swift; sourceTree = "<group>"; };
|
||||||
6773F87EE60F91BBDCA4B1F5 /* GroupConversationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupConversationTests.swift; sourceTree = "<group>"; };
|
6773F87EE60F91BBDCA4B1F5 /* GroupConversationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupConversationTests.swift; sourceTree = "<group>"; };
|
||||||
69F4FFBFD65C218FF6505844 /* SaslFailureMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaslFailureMessage.swift; sourceTree = "<group>"; };
|
69F4FFBFD65C218FF6505844 /* SaslFailureMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaslFailureMessage.swift; sourceTree = "<group>"; };
|
||||||
@@ -417,12 +417,12 @@
|
|||||||
D8C81B9255E9886FB86E0785 /* InlineVideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineVideoPlayer.swift; sourceTree = "<group>"; };
|
D8C81B9255E9886FB86E0785 /* InlineVideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineVideoPlayer.swift; sourceTree = "<group>"; };
|
||||||
D9BBE412EAF54DFE968B2E54 /* ArchiveSyncCheckpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveSyncCheckpoint.swift; sourceTree = "<group>"; };
|
D9BBE412EAF54DFE968B2E54 /* ArchiveSyncCheckpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveSyncCheckpoint.swift; sourceTree = "<group>"; };
|
||||||
D9FCE089ABBF05EF9F55D451 /* VideoNoteRecordingLifecycleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoNoteRecordingLifecycleTests.swift; sourceTree = "<group>"; };
|
D9FCE089ABBF05EF9F55D451 /* VideoNoteRecordingLifecycleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoNoteRecordingLifecycleTests.swift; sourceTree = "<group>"; };
|
||||||
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 = "<group>"; };
|
E619B2C85B0DD2E80653D6D3 /* VideoNoteRecordingCompletionPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoNoteRecordingCompletionPolicy.swift; sourceTree = "<group>"; };
|
||||||
E6A5C32B4DACD56DA733A0DB /* ServerInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerInformation.swift; sourceTree = "<group>"; };
|
E6A5C32B4DACD56DA733A0DB /* ServerInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerInformation.swift; sourceTree = "<group>"; };
|
||||||
E9F226A1F8D82B39630F9CEB /* LumaRoomStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LumaRoomStore.swift; sourceTree = "<group>"; };
|
E9F226A1F8D82B39630F9CEB /* LumaRoomStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LumaRoomStore.swift; sourceTree = "<group>"; };
|
||||||
EA1D94FE541121DAE9DCE3B0 /* LegacyArchiveImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyArchiveImporter.swift; sourceTree = "<group>"; };
|
EA1D94FE541121DAE9DCE3B0 /* LegacyArchiveImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyArchiveImporter.swift; sourceTree = "<group>"; };
|
||||||
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 = "<group>"; };
|
F0A35C9A7B52458996513382 /* WatchVoiceRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchVoiceRecorder.swift; sourceTree = "<group>"; };
|
||||||
F207C1B20DE3780F1754F81D /* ConnectionBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionBanner.swift; sourceTree = "<group>"; };
|
F207C1B20DE3780F1754F81D /* ConnectionBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionBanner.swift; sourceTree = "<group>"; };
|
||||||
F26F91180E43DE9C135B68C1 /* EmojiCatalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCatalog.swift; sourceTree = "<group>"; };
|
F26F91180E43DE9C135B68C1 /* EmojiCatalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCatalog.swift; sourceTree = "<group>"; };
|
||||||
@@ -683,7 +683,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
DF8C531E464C9C4EDE2648C6 /* Luma.app */,
|
DF8C531E464C9C4EDE2648C6 /* Luma.app */,
|
||||||
EA54340DD785335237158BEF /* Luma.app */,
|
EA54340DD785335237158BEF /* LumaMac.app */,
|
||||||
6317FAA29F22A3EA8450208F /* LumaTests.xctest */,
|
6317FAA29F22A3EA8450208F /* LumaTests.xctest */,
|
||||||
19D4E9404712E8643E31CB93 /* LumaWatch.app */,
|
19D4E9404712E8643E31CB93 /* LumaWatch.app */,
|
||||||
);
|
);
|
||||||
@@ -767,7 +767,7 @@
|
|||||||
2A745A82DD6F34F0CB46B52B /* WebRTC */,
|
2A745A82DD6F34F0CB46B52B /* WebRTC */,
|
||||||
);
|
);
|
||||||
productName = LumaMac;
|
productName = LumaMac;
|
||||||
productReference = EA54340DD785335237158BEF /* Luma.app */;
|
productReference = EA54340DD785335237158BEF /* LumaMac.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
BAB78463D7DE07A8F7B3D27D /* LumaWatch */ = {
|
BAB78463D7DE07A8F7B3D27D /* LumaWatch */ = {
|
||||||
@@ -813,7 +813,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
LastUpgradeCheck = 2660;
|
LastUpgradeCheck = 1600;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
0565F6C7DA26F0482928704E = {
|
0565F6C7DA26F0482928704E = {
|
||||||
DevelopmentTeam = K3AS449A74;
|
DevelopmentTeam = K3AS449A74;
|
||||||
@@ -1169,7 +1169,6 @@
|
|||||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Config/LumaMac.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Config/LumaMac.entitlements;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
|
||||||
DEVELOPMENT_TEAM = K3AS449A74;
|
DEVELOPMENT_TEAM = K3AS449A74;
|
||||||
INFOPLIST_FILE = "Config/LumaMac-Info.plist";
|
INFOPLIST_FILE = "Config/LumaMac-Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleIconName = AppIcon;
|
INFOPLIST_KEY_CFBundleIconName = AppIcon;
|
||||||
@@ -1192,7 +1191,6 @@
|
|||||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Config/LumaMac.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Config/LumaMac.entitlements;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
|
||||||
DEVELOPMENT_TEAM = K3AS449A74;
|
DEVELOPMENT_TEAM = K3AS449A74;
|
||||||
INFOPLIST_FILE = "Config/LumaMac-Info.plist";
|
INFOPLIST_FILE = "Config/LumaMac-Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleIconName = AppIcon;
|
INFOPLIST_KEY_CFBundleIconName = AppIcon;
|
||||||
@@ -1290,7 +1288,6 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@@ -1324,7 +1321,6 @@
|
|||||||
COMPANION_BUNDLE_IDENTIFIER = app.luma.chat;
|
COMPANION_BUNDLE_IDENTIFIER = app.luma.chat;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 31;
|
CURRENT_PROJECT_VERSION = 31;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
@@ -1348,7 +1344,6 @@
|
|||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.9;
|
SWIFT_VERSION = 5.9;
|
||||||
@@ -1378,7 +1373,6 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@@ -1412,7 +1406,6 @@
|
|||||||
COMPANION_BUNDLE_IDENTIFIER = app.luma.chat;
|
COMPANION_BUNDLE_IDENTIFIER = app.luma.chat;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 31;
|
CURRENT_PROJECT_VERSION = 31;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
@@ -1429,7 +1422,6 @@
|
|||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
SWIFT_VERSION = 5.9;
|
SWIFT_VERSION = 5.9;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "2660"
|
LastUpgradeVersion = "1600"
|
||||||
version = "1.3">
|
version = "1.7">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
buildImplicitDependencies = "YES">
|
buildImplicitDependencies = "YES"
|
||||||
|
runPostActionsOnFailure = "NO">
|
||||||
<BuildActionEntries>
|
<BuildActionEntries>
|
||||||
<BuildActionEntry
|
<BuildActionEntry
|
||||||
buildForTesting = "YES"
|
buildForTesting = "YES"
|
||||||
@@ -40,7 +41,8 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
onlyGenerateCoverageForSpecifiedTargets = "NO">
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
@@ -63,6 +65,8 @@
|
|||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
@@ -84,6 +88,8 @@
|
|||||||
ReferencedContainer = "container:Luma.xcodeproj">
|
ReferencedContainer = "container:Luma.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "2660"
|
LastUpgradeVersion = "1600"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "2660"
|
LastUpgradeVersion = "1600"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|||||||
@@ -2,12 +2,19 @@ import CoreGraphics
|
|||||||
|
|
||||||
struct MessageReplySwipePolicy {
|
struct MessageReplySwipePolicy {
|
||||||
static let triggerDistance: CGFloat = 64
|
static let triggerDistance: CGFloat = 64
|
||||||
|
/// Horizontal travel required before the reply indicator appears. Keeps
|
||||||
|
/// the per-cell state untouched during ordinary vertical scrolling.
|
||||||
|
static let activationDistance: CGFloat = 24
|
||||||
static let maximumOffset: CGFloat = 76
|
static let maximumOffset: CGFloat = 76
|
||||||
static let horizontalDominance: CGFloat = 1.4
|
/// The drag must be clearly horizontal: a mostly vertical timeline scroll
|
||||||
|
/// (even a diagonal one) must never arm the reply swipe or move bubbles.
|
||||||
|
static let horizontalDominance: CGFloat = 2.0
|
||||||
|
|
||||||
static func offset(for translation: CGSize) -> CGFloat {
|
static func offset(for translation: CGSize) -> CGFloat {
|
||||||
guard isHorizontal(translation) else { return 0 }
|
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
|
return translation.width < 0 ? -distance : distance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -177,9 +177,16 @@ struct MessageBubble: View {
|
|||||||
DragGesture(minimumDistance: 20)
|
DragGesture(minimumDistance: 20)
|
||||||
.onChanged { value in
|
.onChanged { value in
|
||||||
let offset = MessageReplySwipePolicy.offset(for: value.translation)
|
let offset = MessageReplySwipePolicy.offset(for: value.translation)
|
||||||
guard offset != 0 || replySwipeOffset != 0 else {
|
guard offset != 0 else {
|
||||||
// A vertical timeline pan must not publish per-cell state
|
// Vertical (or not clearly horizontal) movement: snap the
|
||||||
// changes or compete with UIScrollView's own recognizer.
|
// 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
|
return
|
||||||
}
|
}
|
||||||
replySwipeOffset = offset
|
replySwipeOffset = offset
|
||||||
|
|||||||
@@ -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() {
|
func testVisualOffsetIsCapped() {
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
MessageReplySwipePolicy.offset(for: CGSize(width: 500, height: 0)),
|
MessageReplySwipePolicy.offset(for: CGSize(width: 500, height: 0)),
|
||||||
|
|||||||
Reference in new issue
Block a user