forked from Archives/Athou_commafeed
mark all as read
This commit is contained in:
@@ -40,7 +40,7 @@ public class FeedEntryService extends GenericDAO<FeedEntry, Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TypedQuery<FeedEntry> unreadQuery(Feed feed, User user) {
|
private TypedQuery<FeedEntry> unreadQuery(Feed feed, User user) {
|
||||||
String query = "select e from FeedEntry e where e.feed=:feed and not exists (select s from FeedEntryStatus s where s.entry = e and s.user =:user and s.read = true)";
|
String query = "select e from FeedEntry e where e.feed =:feed and not exists (select s from FeedEntryStatus s where s.entry = e and s.user =:user and s.read = true)";
|
||||||
TypedQuery<FeedEntry> typedQuery = em.createQuery(query,
|
TypedQuery<FeedEntry> typedQuery = em.createQuery(query,
|
||||||
FeedEntry.class);
|
FeedEntry.class);
|
||||||
typedQuery.setParameter("feed", feed);
|
typedQuery.setParameter("feed", feed);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.commafeed.backend.feeds;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.ejb.Schedule;
|
import javax.ejb.Schedule;
|
||||||
import javax.ejb.Singleton;
|
import javax.ejb.Singleton;
|
||||||
@@ -46,7 +47,7 @@ public class FeedTimer {
|
|||||||
for (String key : futures.keySet()) {
|
for (String key : futures.keySet()) {
|
||||||
Future<Feed> future = futures.get(key);
|
Future<Feed> future = futures.get(key);
|
||||||
try {
|
try {
|
||||||
Feed feed = future.get();
|
Feed feed = future.get(1, TimeUnit.MINUTES);
|
||||||
feedEntryService
|
feedEntryService
|
||||||
.updateEntries(feed.getUrl(), feed.getEntries());
|
.updateEntries(feed.getUrl(), feed.getEntries());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import java.util.List;
|
|||||||
import javax.ws.rs.DefaultValue;
|
import javax.ws.rs.DefaultValue;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
|
|
||||||
import org.apache.commons.lang.ObjectUtils;
|
import org.apache.commons.lang.ObjectUtils;
|
||||||
|
|
||||||
|
import com.commafeed.backend.model.Feed;
|
||||||
import com.commafeed.backend.model.FeedCategory;
|
import com.commafeed.backend.model.FeedCategory;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.FeedEntryStatus;
|
import com.commafeed.backend.model.FeedEntryStatus;
|
||||||
@@ -30,7 +30,7 @@ public class EntriesREST extends AbstractREST {
|
|||||||
private static final String ALL = "all";
|
private static final String ALL = "all";
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
category, feed;
|
category, feed, entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ReadType {
|
public enum ReadType {
|
||||||
@@ -132,22 +132,42 @@ public class EntriesREST extends AbstractREST {
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("mark/{type}/{id}/{read}")
|
@Path("mark")
|
||||||
@GET
|
@GET
|
||||||
public void mark(@PathParam("type") String type,
|
public void mark(@QueryParam("type") Type type,
|
||||||
@PathParam("id") String id, @PathParam("read") boolean read) {
|
@QueryParam("id") String id, @QueryParam("read") boolean read) {
|
||||||
if ("entry".equals(type)) {
|
Preconditions.checkNotNull(type);
|
||||||
|
Preconditions.checkNotNull(id);
|
||||||
|
Preconditions.checkNotNull(read);
|
||||||
|
|
||||||
|
if (type == Type.entry) {
|
||||||
FeedEntry entry = feedEntryService.findById(Long.valueOf(id));
|
FeedEntry entry = feedEntryService.findById(Long.valueOf(id));
|
||||||
FeedEntryStatus status = feedEntryStatusService.getStatus(
|
markEntry(entry, read);
|
||||||
getUser(), entry);
|
} else if (type == Type.feed) {
|
||||||
if (status == null) {
|
List<FeedEntry> entries = null;
|
||||||
status = new FeedEntryStatus();
|
Feed feed = feedSubscriptionService.findById(Long.valueOf(id))
|
||||||
status.setUser(getUser());
|
.getFeed();
|
||||||
status.setEntry(entry);
|
if (read) {
|
||||||
|
entries = feedEntryService.getUnreadEntries(feed, getUser());
|
||||||
|
} else {
|
||||||
|
entries = feedEntryService.getAllEntries(feed);
|
||||||
|
}
|
||||||
|
for (FeedEntry entry : entries) {
|
||||||
|
markEntry(entry, read);
|
||||||
}
|
}
|
||||||
status.setRead(read);
|
|
||||||
feedEntryStatusService.saveOrUpdate(status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void markEntry(FeedEntry entry, boolean read) {
|
||||||
|
FeedEntryStatus status = feedEntryStatusService.getStatus(getUser(),
|
||||||
|
entry);
|
||||||
|
if (status == null) {
|
||||||
|
status = new FeedEntryStatus();
|
||||||
|
status.setUser(getUser());
|
||||||
|
status.setEntry(entry);
|
||||||
|
}
|
||||||
|
status.setRead(read);
|
||||||
|
feedEntryStatusService.saveOrUpdate(status);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,14 +27,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* entry list*/
|
/* entry list*/
|
||||||
.entry {
|
#feed-accordion .entry {
|
||||||
border-bottom: 1px solid #CCCCCC;
|
border-bottom: 1px solid #CCCCCC;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry:hover {
|
.no-entries {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry .entry-heading a {
|
||||||
|
padding: 6px 0px;
|
||||||
background-color: #EBEBEB;
|
background-color: #EBEBEB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entry .entry-heading a.collapsed {
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry .entry-heading a.collapsed:hover {
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry .entry-heading a ~.collapsed {
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
padding: 6px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.entry a {
|
.entry a {
|
||||||
color: black;
|
color: black;
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="btn" ng-click="refresh()"><i class="icon-refresh"></i> Refresh</button>
|
<button type="button" class="btn" ng-click="refresh()"><i class="icon-refresh"></i> Refresh</button>
|
||||||
<button type="button" class="btn"><i class="icon-ok"></i> Mark all as read</button>
|
<button type="button" class="btn" ng-click="markAllAsRead()"><i class="icon-ok"></i> Mark all as read</button>
|
||||||
|
|
||||||
<div class="btn-group pull-right">
|
<div class="btn-group pull-right">
|
||||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="settings"><i class="icon-cog"></i><span class="caret"></span></a>
|
<a class="btn dropdown-toggle" data-toggle="dropdown" href="settings"><i class="icon-cog"></i><span class="caret"></span></a>
|
||||||
|
|||||||
@@ -152,9 +152,9 @@ module.controller('FeedListCtrl', function($scope, $routeParams, $http,
|
|||||||
entry : entry
|
entry : entry
|
||||||
});
|
});
|
||||||
EntryService.mark({
|
EntryService.mark({
|
||||||
_type : 'entry',
|
type : 'entry',
|
||||||
_id : entry.id,
|
id : entry.id,
|
||||||
_readtype : read
|
read : read
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ module.directive('category', function($compile) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
module.directive('toolbar', function(SettingsService) {
|
module.directive('toolbar', function($routeParams, $route, SettingsService, EntryService, SubscriptionService) {
|
||||||
return {
|
return {
|
||||||
scope : {},
|
scope : {},
|
||||||
restrict : 'E',
|
restrict : 'E',
|
||||||
@@ -99,6 +99,17 @@ module.directive('toolbar', function(SettingsService) {
|
|||||||
$scope.settings = SettingsService.settings;
|
$scope.settings = SettingsService.settings;
|
||||||
$scope.refresh = function() {
|
$scope.refresh = function() {
|
||||||
$route.reload();
|
$route.reload();
|
||||||
|
},
|
||||||
|
$scope.markAllAsRead = function() {
|
||||||
|
EntryService.mark({
|
||||||
|
type: $routeParams._type,
|
||||||
|
id: $routeParams._id,
|
||||||
|
read: true,
|
||||||
|
}, function() {
|
||||||
|
SubscriptionService.init(function() {
|
||||||
|
$route.reload();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
link : function($scope, element) {
|
link : function($scope, element) {
|
||||||
|
|||||||
@@ -41,9 +41,10 @@ module.factory('SubscriptionService', [ '$resource', '$http',
|
|||||||
s.flatCategories = {};
|
s.flatCategories = {};
|
||||||
|
|
||||||
var res = $resource('rest/subscriptions/:_method', {}, actions);
|
var res = $resource('rest/subscriptions/:_method', {}, actions);
|
||||||
s.init = function() {
|
s.init = function(callback) {
|
||||||
s.subscriptions = res.get(function(){
|
s.subscriptions = res.get(function(data) {
|
||||||
s.flatCategories = flatten(s.subscriptions);
|
s.flatCategories = flatten(s.subscriptions);
|
||||||
|
callback(data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
s.subscribe = function(sub, callback) {
|
s.subscribe = function(sub, callback) {
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
{{readType}}
|
{{readType}}
|
||||||
<span>{{entryList.name}}</span><span
|
<span>{{entryList.name}}</span><span
|
||||||
ng-show="selectedType == 'category'"> »</span>
|
ng-show="selectedType == 'category'"> »</span>
|
||||||
<div class="accordion" id="feed-accordion" infinite-scroll="loadMoreEntries()" infinite-scroll-disabled="busy" infinite-scroll-distance="1">
|
<div id="feed-accordion" infinite-scroll="loadMoreEntries()" infinite-scroll-disabled="busy" infinite-scroll-distance="1">
|
||||||
<div ng-repeat="entry in entryList.entries" class="entry">
|
<div ng-repeat="entry in entryList.entries" class="entry">
|
||||||
<div class="entry-heading">
|
<div class="entry-heading">
|
||||||
<a class="accordion-toggle" data-toggle="collapse"
|
<a class="accordion-toggle collapsed" data-toggle="collapse"
|
||||||
ng-click="mark(entry, true)"
|
ng-click="mark(entry, true)"
|
||||||
ng-class="{unread: entry.read == false}"
|
ng-class="{unread: entry.read == false}"
|
||||||
data-parent="#feed-accordion" href="{{'#feed-body' + $index}}">
|
data-parent="#feed-accordion" href="{{'#feed-body' + $index}}">
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="no-entries" ng-show="entryList.entries.length == 0">"{{entryList.name}}" has no unread items.</div>
|
||||||
<div ng-show="busy">Loading data...</div>
|
<div ng-show="busy">Loading data...</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user