From df8f6b5fee643c5b2af8e8d33a7865e898518485 Mon Sep 17 00:00:00 2001 From: Bernhard Posselt Date: Sat, 14 Sep 2013 02:22:36 +0200 Subject: implement pull to refresh, fix #44 --- js/app/controllers/itemcontroller.coffee | 5 ++ js/app/directives/pulltorefresh.coffee | 30 ++++++++ .../businesslayer/itembusinesslayer.coffee | 8 ++- js/app/services/models/itemmodel.coffee | 14 +++- js/app/services/persistence.coffee | 13 ++++ js/public/app.js | 82 +++++++++++++++++++++- js/tests/controllers/itemcontrollerSpec.coffee | 15 ++++ .../businesslayer/itembusinesslayerSpec.coffee | 16 +++++ js/tests/services/models/itemmodelSpec.coffee | 11 ++- js/tests/services/persistenceSpec.coffee | 16 +++++ 10 files changed, 203 insertions(+), 7 deletions(-) create mode 100644 js/app/directives/pulltorefresh.coffee (limited to 'js') diff --git a/js/app/controllers/itemcontroller.coffee b/js/app/controllers/itemcontroller.coffee index eac508e18..c9a97285f 100644 --- a/js/app/controllers/itemcontroller.coffee +++ b/js/app/controllers/itemcontroller.coffee @@ -58,6 +58,11 @@ Language, AutoPageLoading) -> else return '' + @_$scope.loadNew = => + @_$scope.refresh = true + @_itemBusinessLayer.loadNew => + @_$scope.refresh = false + @_$scope.$on 'readItem', (scope, data) => @_itemBusinessLayer.setRead(data) diff --git a/js/app/directives/pulltorefresh.coffee b/js/app/directives/pulltorefresh.coffee new file mode 100644 index 000000000..436280793 --- /dev/null +++ b/js/app/directives/pulltorefresh.coffee @@ -0,0 +1,30 @@ +### + +ownCloud - News + +@author Bernhard Posselt +@copyright 2012 Bernhard Posselt dev@bernhard-posselt.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +License as published by the Free Software Foundation; either +version 3 of the License, or any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU AFFERO GENERAL PUBLIC LICENSE for more details. + +You should have received a copy of the GNU Affero General Public +License along with this library. If not, see . + +### + +angular.module('News').directive 'newsPullToRefresh', -> + directive = + restrict: 'A' + link: (scope, elm, attrs) -> + scrollTop = 0 + elm.scroll -> + if @scrollTop == 0 + scope.$apply attrs.newsPullToRefresh \ No newline at end of file diff --git a/js/app/services/businesslayer/itembusinesslayer.coffee b/js/app/services/businesslayer/itembusinesslayer.coffee index 0563ff096..1382df190 100644 --- a/js/app/services/businesslayer/itembusinesslayer.coffee +++ b/js/app/services/businesslayer/itembusinesslayer.coffee @@ -116,8 +116,12 @@ StarredBusinessLayer, NewestItem) -> callback() - - loadNew: -> + loadNew: (onSuccess) -> + lastModified = @_itemModel.getLastModified() + @_persistence.getNewItems(@_activeFeed.getType(), + @_activeFeed.getId(), + lastModified, + onSuccess) diff --git a/js/app/services/models/itemmodel.coffee b/js/app/services/models/itemmodel.coffee index 349147ca5..7da924be3 100644 --- a/js/app/services/models/itemmodel.coffee +++ b/js/app/services/models/itemmodel.coffee @@ -21,8 +21,8 @@ License along with this library. If not, see . ### angular.module('News').factory 'ItemModel', -['_Model', '_MinimumQuery', 'StatusFlag', -(_Model, _MinimumQuery, StatusFlag) -> +['_Model', '_MinimumQuery', '_MaximumQuery', 'StatusFlag', +(_Model, _MinimumQuery, _MaximumQuery, StatusFlag) -> class ItemModel extends _Model @@ -109,5 +109,15 @@ angular.module('News').factory 'ItemModel', return 0 + getLastModified: -> + query = new _MaximumQuery('lastModified') + lastModified = @get(query) + + if angular.isDefined(lastModified) + return lastModified.lastModified + else + return 0 + + return new ItemModel() ] \ No newline at end of file diff --git a/js/app/services/persistence.coffee b/js/app/services/persistence.coffee index 559601f69..d51c7acb1 100644 --- a/js/app/services/persistence.coffee +++ b/js/app/services/persistence.coffee @@ -86,6 +86,19 @@ $rootScope, $q) -> @_request.get 'news_items', params + getNewItems: (type, id, lastModified, onSuccess) -> + onSuccess or= -> + params = + data: + type: type + id: id + lastModified: lastModified + onSuccess: onSuccess + onFailure: onSuccess + + @_request.get 'news_items_new', params + + starItem: (feedId, guidHash) -> ### Stars an item diff --git a/js/public/app.js b/js/public/app.js index cd822b6a4..ab237c645 100644 --- a/js/public/app.js +++ b/js/public/app.js @@ -451,6 +451,48 @@ License along with this library. If not, see . */ +(function() { + angular.module('News').directive('newsPullToRefresh', function() { + var directive; + return directive = { + restrict: 'A', + link: function(scope, elm, attrs) { + var scrollTop; + scrollTop = 0; + return elm.scroll(function() { + if (this.scrollTop === 0) { + return scope.$apply(attrs.newsPullToRefresh); + } + }); + } + }; + }); + +}).call(this); + +// Generated by CoffeeScript 1.6.3 +/* + +ownCloud - News + +@author Bernhard Posselt +@copyright 2012 Bernhard Posselt dev@bernhard-posselt.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +License as published by the Free Software Foundation; either +version 3 of the License, or any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU AFFERO GENERAL PUBLIC LICENSE for more details. + +You should have received a copy of the GNU Affero General Public +License along with this library. If not, see . +*/ + + (function() { angular.module('News').directive('undoNotification', [ '$rootScope', '$timeout', 'Config', function($rootScope, $timeout, Config) { @@ -735,6 +777,12 @@ License along with this library. If not, see . return ''; } }; + this._$scope.loadNew = function() { + _this._$scope.refresh = true; + return _this._itemBusinessLayer.loadNew(function() { + return _this._$scope.refresh = false; + }); + }; this._$scope.$on('readItem', function(scope, data) { return _this._itemBusinessLayer.setRead(data); }); @@ -1525,7 +1573,11 @@ License along with this library. If not, see . } }; - ItemBusinessLayer.prototype.loadNew = function() {}; + ItemBusinessLayer.prototype.loadNew = function(onSuccess) { + var lastModified; + lastModified = this._itemModel.getLastModified(); + return this._persistence.getNewItems(this._activeFeed.getType(), this._activeFeed.getId(), lastModified, onSuccess); + }; return ItemBusinessLayer; @@ -2212,7 +2264,7 @@ License along with this library. If not, see . __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; angular.module('News').factory('ItemModel', [ - '_Model', '_MinimumQuery', 'StatusFlag', function(_Model, _MinimumQuery, StatusFlag) { + '_Model', '_MinimumQuery', '_MaximumQuery', 'StatusFlag', function(_Model, _MinimumQuery, _MaximumQuery, StatusFlag) { var ItemModel; ItemModel = (function(_super) { __extends(ItemModel, _super); @@ -2309,6 +2361,17 @@ License along with this library. If not, see . } }; + ItemModel.prototype.getLastModified = function() { + var lastModified, query; + query = new _MaximumQuery('lastModified'); + lastModified = this.get(query); + if (angular.isDefined(lastModified)) { + return lastModified.lastModified; + } else { + return 0; + } + }; + return ItemModel; })(_Model); @@ -2574,6 +2637,21 @@ License along with this library. If not, see . return this._request.get('news_items', params); }; + Persistence.prototype.getNewItems = function(type, id, lastModified, onSuccess) { + var params; + onSuccess || (onSuccess = function() {}); + params = { + data: { + type: type, + id: id, + lastModified: lastModified + }, + onSuccess: onSuccess, + onFailure: onSuccess + }; + return this._request.get('news_items_new', params); + }; + Persistence.prototype.starItem = function(feedId, guidHash) { /* Stars an item diff --git a/js/tests/controllers/itemcontrollerSpec.coffee b/js/tests/controllers/itemcontrollerSpec.coffee index b06e16a9c..27fc82f71 100644 --- a/js/tests/controllers/itemcontrollerSpec.coffee +++ b/js/tests/controllers/itemcontrollerSpec.coffee @@ -169,3 +169,18 @@ describe 'ItemController', -> expect(@persistence.getItems.callCount).toBe(2) + + it 'should set refresh to true when pull to refresh is activated', => + @ItemBusinessLayer.loadNew = -> + + @scope.loadNew() + expect(@scope.refresh).toBe(true) + + + it 'should set refresh to false after load next was successful', => + @ItemBusinessLayer.loadNew = jasmine.createSpy('loadNew') + @ItemBusinessLayer.loadNew.andCallFake (callback) -> + callback() + + @scope.loadNew() + expect(@scope.refresh).toBe(false) \ No newline at end of file diff --git a/js/tests/services/businesslayer/itembusinesslayerSpec.coffee b/js/tests/services/businesslayer/itembusinesslayerSpec.coffee index e14ba54b3..75804323d 100644 --- a/js/tests/services/businesslayer/itembusinesslayerSpec.coffee +++ b/js/tests/services/businesslayer/itembusinesslayerSpec.coffee @@ -248,3 +248,19 @@ describe 'ItemBusinessLayer', -> expect(@persistence.getItems).toHaveBeenCalledWith( @FeedType.Feed, 3, 1, jasmine.any(Function)) + + + it 'should load the next items', => + @NewestItem.handle(13) + @persistence.getNewItems = jasmine.createSpy('loadnew') + callback = -> + + @ItemModel.add({id: 2, guidHash: 'abc', feedId: 2, lastModified: 2}) + @ItemModel.add({id: 3, guidHash: 'abcd', feedId: 2, lastModified: 4}) + @ItemModel.add({id: 1, guidHash: 'abce', feedId: 2, lastModified: 3}) + @ItemModel.add({id: 6, guidHash: 'abcf', feedId: 2, lastModified: 1}) + + @ItemBusinessLayer.loadNew(callback) + + expect(@persistence.getNewItems).toHaveBeenCalledWith( + @FeedType.Feed, 3, 4, callback) diff --git a/js/tests/services/models/itemmodelSpec.coffee b/js/tests/services/models/itemmodelSpec.coffee index 4decc7918..d2fed6630 100644 --- a/js/tests/services/models/itemmodelSpec.coffee +++ b/js/tests/services/models/itemmodelSpec.coffee @@ -110,4 +110,13 @@ describe 'ItemModel', -> @ItemModel.add({id: 1, guidHash: 'abce', feedId: 2, status: 16}) @ItemModel.add({id: 6, guidHash: 'abcf', feedId: 2, status: 16}) - expect(@ItemModel.getLowestId()).toBe(1) \ No newline at end of file + expect(@ItemModel.getLowestId()).toBe(1) + + + it 'should return the highest lastModified', => + @ItemModel.add({id: 2, guidHash: 'abc', feedId: 2, lastModified: 3}) + @ItemModel.add({id: 3, guidHash: 'abcd', feedId: 2, lastModified: 13}) + @ItemModel.add({id: 1, guidHash: 'abce', feedId: 2, lastModified: 15}) + @ItemModel.add({id: 6, guidHash: 'abcf', feedId: 2, lastModified: 11}) + + expect(@ItemModel.getLastModified()).toBe(15) \ No newline at end of file diff --git a/js/tests/services/persistenceSpec.coffee b/js/tests/services/persistenceSpec.coffee index e9f12f669..38e02705a 100644 --- a/js/tests/services/persistenceSpec.coffee +++ b/js/tests/services/persistenceSpec.coffee @@ -74,6 +74,22 @@ describe 'Persistence', -> expect(@req.get).toHaveBeenCalledWith('news_items', expected) + it 'should send a load new items request', => + success = -> + params = + data: + type: 2 + id: 5 + lastModified: 3 + onSuccess: success + onFailure: success + + @Persistence.getNewItems(params.data.type, params.data.id, + params.data.lastModified, success) + + expect(@req.get).toHaveBeenCalledWith('news_items_new', params) + + it 'send a correct star item request', => params = routeParams: -- cgit v1.2.3