diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index 0156877e8..da8f56219 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -13,6 +13,7 @@ const Main = imports.ui.main; const PageIndicators = imports.ui.pageIndicators; const PopupMenu = imports.ui.popupMenu; const Search = imports.ui.search; +const SwipeTracker = imports.ui.swipeTracker; const Params = imports.misc.params; const Util = imports.misc.util; const SystemActions = imports.misc.systemActions; @@ -327,7 +328,9 @@ var AllView = GObject.registerClass({ (indicators, pageIndex) => { this.goToPage(pageIndex); }); - this._pageIndicators.connect('scroll-event', this._onScroll.bind(this)); + this._pageIndicators.connect('scroll-event', (actor, event) => { + this._scrollView.event(event, false); + }); this.add_actor(this._pageIndicators); this._folderIcons = []; @@ -353,13 +356,12 @@ var AllView = GObject.registerClass({ this._scrollView.connect('scroll-event', this._onScroll.bind(this)); - let panAction = new Clutter.PanAction({ interpolate: false }); - panAction.connect('pan', this._onPan.bind(this)); - panAction.connect('gesture-cancel', this._onPanEnd.bind(this)); - panAction.connect('gesture-end', this._onPanEnd.bind(this)); - this._panAction = panAction; - this._scrollView.add_action(panAction); - this._panning = false; + this._swipeTracker = new SwipeTracker.SwipeTracker( + this._scrollView, Shell.ActionMode.OVERVIEW); + this._swipeTracker.connect('begin', this._swipeBegin.bind(this)); + this._swipeTracker.connect('update', this._swipeUpdate.bind(this)); + this._swipeTracker.connect('end', this._swipeEnd.bind(this)); + this._clickAction = new Clutter.ClickAction(); this._clickAction.connect('clicked', () => { if (!this._currentPopup) @@ -424,6 +426,7 @@ var AllView = GObject.registerClass({ this._keyPressEventId = global.stage.connect('key-press-event', this._onKeyPressEvent.bind(this)); + this._swipeTracker.enabled = true; super.vfunc_map(); } @@ -432,6 +435,7 @@ var AllView = GObject.registerClass({ global.stage.disconnect(this._keyPressEventId); this._keyPressEventId = 0; } + this._swipeTracker.enabled = false; super.vfunc_unmap(); } @@ -577,7 +581,7 @@ var AllView = GObject.registerClass({ return this._grid.getPageY(this._grid.currentPage); } - goToPage(pageNumber) { + goToPage(pageNumber, animate = true) { pageNumber = clamp(pageNumber, 0, this._grid.nPages() - 1); if (this._grid.currentPage == pageNumber && this._displayingPopup && this._currentPopup) @@ -592,42 +596,16 @@ var AllView = GObject.registerClass({ return; } - let velocity; - if (!this._panning) - velocity = 0; - else - velocity = Math.abs(this._panAction.get_velocity(0)[2]); - // Tween the change between pages. - // If velocity is not specified (i.e. scrolling with mouse wheel), - // use the same speed regardless of original position - // if velocity is specified, it's in pixels per milliseconds - let diffToPage = this._diffToPage(pageNumber); - let childBox = this._scrollView.get_allocation_box(); - let totalHeight = childBox.y2 - childBox.y1; - let time; - // Only take the velocity into account on page changes, otherwise - // return smoothly to the current page using the default velocity - if (this._grid.currentPage != pageNumber) { - let minVelocity = totalHeight / PAGE_SWITCH_TIME; - velocity = Math.max(minVelocity, velocity); - time = diffToPage / velocity; - } else { - time = PAGE_SWITCH_TIME * diffToPage / totalHeight; - } - // When changing more than one page, make sure to not take - // longer than PAGE_SWITCH_TIME - time = Math.min(time, PAGE_SWITCH_TIME); + if (this._grid.currentPage === pageNumber) + return; this._grid.currentPage = pageNumber; - this._adjustment.ease(this._grid.getPageY(pageNumber), { - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - duration: time, - }); - } - _diffToPage(pageNumber) { - let currentScrollPosition = this._adjustment.value; - return Math.abs(currentScrollPosition - this._grid.getPageY(pageNumber)); + // Tween the change between pages. + this._adjustment.ease(this._grid.getPageY(this._grid.currentPage), { + mode: Clutter.AnimationMode.EASE_OUT_CUBIC, + duration: animate ? PAGE_SWITCH_TIME : 0, + }); } openSpaceForPopup(item, side, nRows) { @@ -650,6 +628,9 @@ var AllView = GObject.registerClass({ if (this._displayingPopup || !this._scrollView.reactive) return Clutter.EVENT_STOP; + if (this._swipeTracker.canHandleScrollEvent(event)) + return Clutter.EVENT_PROPAGATE; + if (!this._canScroll) return Clutter.EVENT_STOP; @@ -673,34 +654,36 @@ var AllView = GObject.registerClass({ return Clutter.EVENT_STOP; } - _onPan(action) { - if (this._displayingPopup) - return false; - this._panning = true; - this._clickAction.release(); - let [dist_, dx_, dy] = action.get_motion_delta(0); - let adjustment = this._adjustment; - adjustment.value -= (dy / this._scrollView.height) * adjustment.page_size; - return false; - } - - _onPanEnd(action) { - if (this._displayingPopup) + _swipeBegin(tracker, monitor) { + if (monitor !== Main.layoutManager.primaryIndex) return; - let pageHeight = this._grid.getPageHeight(); + let adjustment = this._adjustment; + adjustment.remove_transition('value'); - // Calculate the scroll value we'd be at, which is our current - // scroll plus any velocity the user had when they released - // their finger. + let progress = adjustment.value / adjustment.page_size; + let points = Array.from({ length: this._grid.nPages() }, (v, i) => i); - let velocity = -action.get_velocity(0)[2]; - let endPanValue = this._adjustment.value + velocity; + tracker.confirmSwipe(this._scrollView.height, + points, progress, Math.round(progress)); + } - let closestPage = Math.round(endPanValue / pageHeight); - this.goToPage(closestPage); + _swipeUpdate(tracker, progress) { + let adjustment = this._adjustment; + adjustment.value = progress * adjustment.page_size; + } - this._panning = false; + _swipeEnd(tracker, duration, endProgress) { + let adjustment = this._adjustment; + let value = endProgress * adjustment.page_size; + + adjustment.ease(value, { + mode: Clutter.AnimationMode.EASE_OUT_CUBIC, + duration, + onComplete: () => { + this.goToPage(endProgress, false); + }, + }); } _onKeyPressEvent(actor, event) {