| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:ui'; |
| |
| import 'package:flutter/foundation.dart'; |
| |
| /// Enum representing the edge from which a swipe starts in a back gesture. |
| /// |
| /// This is used in [PredictiveBackEvent] to indicate the starting edge of the |
| /// swipe gesture. |
| enum SwipeEdge { |
| /// Indicates that the swipe gesture starts from the left edge of the screen. |
| left, |
| |
| /// Indicates that the swipe gesture starts from the right edge of the screen. |
| right, |
| } |
| |
| /// Object used to report back gesture progress in Android. |
| /// |
| /// Holds information about the touch event, swipe direction, and the animation |
| /// progress that predictive back animations should follow. |
| @immutable |
| final class PredictiveBackEvent { |
| /// Creates a new [PredictiveBackEvent] instance. |
| const PredictiveBackEvent._({ |
| required this.touchOffset, |
| required this.progress, |
| required this.swipeEdge, |
| }) : assert(progress >= 0.0 && progress <= 1.0); |
| |
| /// Creates an [PredictiveBackEvent] from a Map, typically used when converting |
| /// data received from a platform channel. |
| factory PredictiveBackEvent.fromMap(Map<String?, Object?> map) { |
| final List<Object?>? touchOffset = map['touchOffset'] as List<Object?>?; |
| return PredictiveBackEvent._( |
| touchOffset: |
| touchOffset == null |
| ? null |
| : Offset((touchOffset[0]! as num).toDouble(), (touchOffset[1]! as num).toDouble()), |
| progress: (map['progress']! as num).toDouble(), |
| swipeEdge: SwipeEdge.values[map['swipeEdge']! as int], |
| ); |
| } |
| |
| /// The global position of the touch point as an `Offset`, or `null` if the |
| /// event is triggered by a button press. |
| /// |
| /// This represents the touch location that initiates or interacts with the |
| /// back gesture. When `null`, it indicates the gesture was not started by a |
| /// touch event, such as a back button press in devices with hardware buttons. |
| final Offset? touchOffset; |
| |
| /// Returns a value between 0.0 and 1.0 representing how far along the back |
| /// gesture is. |
| /// |
| /// This value is driven by the horizontal location of the touch point, and |
| /// should be used as the fraction to seek the predictive back animation with. |
| /// Specifically, |
| /// |
| /// - The progress is 0.0 when the touch is at the starting edge of the screen |
| /// (left or right), and the animation should seek to its start state. |
| /// - The progress is approximately 1.0 when the touch is at the opposite side |
| /// of the screen, and the animation should seek to its end state. Exact end |
| /// value may vary depending on screen size. |
| /// |
| /// When the gesture is canceled, the progress value continues to update, |
| /// animating back to 0.0 until the cancellation animation completes. |
| /// |
| /// In-between locations are linearly interpolated based on horizontal |
| /// distance from the starting edge and smooth clamped to 1.0 when the |
| /// distance exceeds a system-wide threshold. |
| final double progress; |
| |
| /// The screen edge from which the swipe gesture starts. |
| final SwipeEdge swipeEdge; |
| |
| /// Indicates if the event was triggered by a system back button press. |
| /// |
| /// Returns false for a predictive back gesture. |
| bool get isButtonEvent => |
| // The Android documentation for BackEvent |
| // (https://developer.android.com/reference/android/window/BackEvent#getTouchX()) |
| // says that getTouchX and getTouchY should return NaN when the system |
| // back button is pressed, but in practice it seems to return 0.0, hence |
| // the check for Offset.zero here. This was tested directly in the engine |
| // on Android emulator running API 34. |
| touchOffset == null || (progress == 0.0 && touchOffset == Offset.zero); |
| |
| @override |
| bool operator ==(Object other) { |
| if (identical(this, other)) { |
| return true; |
| } |
| if (other.runtimeType != runtimeType) { |
| return false; |
| } |
| return other is PredictiveBackEvent && |
| touchOffset == other.touchOffset && |
| progress == other.progress && |
| swipeEdge == other.swipeEdge; |
| } |
| |
| @override |
| int get hashCode => Object.hash(touchOffset, progress, swipeEdge); |
| |
| @override |
| String toString() { |
| return 'PredictiveBackEvent{touchOffset: $touchOffset, progress: $progress, swipeEdge: $swipeEdge}'; |
| } |
| } |