// Copyright 2015 The Chromium 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 '../animation/generators.dart'; import '../animation/mechanics.dart'; import '../animation/scroll_behavior.dart'; import '../fn.dart'; import '../theme/view-configuration.dart' as config; import 'dart:math' as math; import 'dart:sky' as sky; const double _kMillisecondsPerSecond = 1000.0; double _velocityForFlingGesture(sky.GestureEvent event) { return math.max(-config.kMaxFlingVelocity, math.min(config.kMaxFlingVelocity, -event.velocityY)) / _kMillisecondsPerSecond; } abstract class Scrollable extends Component { ScrollBehavior scrollBehavior; double get scrollOffset => _scrollOffset; double _scrollOffset = 0.0; Simulation _simulation; Scrollable({Object key, this.scrollBehavior}) : super(key: key) { events.listen('pointerdown', _handlePointerDown); events.listen('pointerup', _handlePointerUpOrCancel); events.listen('pointercancel', _handlePointerUpOrCancel); events.listen('gestureflingstart', _handleFlingStart); events.listen('gestureflingcancel', _handleFlingCancel); events.listen('gesturescrollupdate', _handleScrollUpdate); events.listen('wheel', _handleWheel); } void didUnmount() { super.didUnmount(); _stopSimulation(); } bool scrollBy(double scrollDelta) { var newScrollOffset = scrollBehavior.applyCurve(_scrollOffset, scrollDelta); if (newScrollOffset == _scrollOffset) return false; setState(() { _scrollOffset = newScrollOffset; }); return true; } void _stopSimulation() { if (_simulation == null) return; _simulation.cancel(); _simulation = null; } void _startSimulation(Particle particle) { _stopSimulation(); _simulation = scrollBehavior.release(particle); if (_simulation == null) return; _simulation.onTick.listen((_) { setState(() { _scrollOffset = particle.position; }); }); } Particle _createParticle([double velocity = 0.0]) { return new Particle(position: _scrollOffset, velocity: velocity); } void _handlePointerDown(_) { _stopSimulation(); } void _handlePointerUpOrCancel(_) { if (_simulation == null) _startSimulation(_createParticle()); } void _handleScrollUpdate(sky.GestureEvent event) { scrollBy(-event.dy); } void _handleFlingStart(sky.GestureEvent event) { _startSimulation(_createParticle(_velocityForFlingGesture(event))); } void _handleFlingCancel(sky.GestureEvent event) { _startSimulation(_createParticle()); } void _handleWheel(sky.WheelEvent event) { scrollBy(-event.offsetY); } }