diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/panels/NewsFeedPanel.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/panels/NewsFeedPanel.java index 27b963e..047ab2c 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/panels/NewsFeedPanel.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/panels/NewsFeedPanel.java @@ -1,6 +1,7 @@ package org.gcube.portlets.user.newsfeed.client.panels; import java.util.ArrayList; +import java.util.Date; import org.gcube.portal.databook.shared.ClientFeed; import org.gcube.portal.databook.shared.Comment; @@ -30,6 +31,7 @@ import org.gcube.portlets.user.newsfeed.client.event.StopTimerEvent; import org.gcube.portlets.user.newsfeed.client.event.StopTimerEventHandler; import org.gcube.portlets.user.newsfeed.client.panels.dialog.LikesDialog; import org.gcube.portlets.user.newsfeed.client.templates.FilterPanel; +import org.gcube.portlets.user.newsfeed.client.templates.NewFeedsAvailable; import org.gcube.portlets.user.newsfeed.client.templates.SingleComment; import org.gcube.portlets.user.newsfeed.client.templates.TweetTemplate; import org.gcube.portlets.user.newsfeed.shared.EnhancedFeed; @@ -47,6 +49,7 @@ import com.google.gwt.user.client.ui.HasAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.VerticalPanel; /** * @@ -63,18 +66,21 @@ public class NewsFeedPanel extends Composite { private VerticalPanel mainPanel = new VerticalPanel(); private HorizontalPanel filterPanel = new HorizontalPanel(); + private SimplePanel newUpdatesPanel = new SimplePanel(); private VerticalPanel newsPanel = new VerticalPanel(); private static final String warning = GWT.getModuleBaseURL() + "../images/warning_blue.png"; private static final String spacer = GWT.getModuleBaseURL() + "../images/feeds-spacer.gif"; public static final String loading = GWT.getModuleBaseURL() + "../images/feeds-loader.gif"; - + public static final String LIKE_LABEL = "Favorite"; public static final String LIKED_LABEL = "Favorited"; public static final String COMMENT_LABEL = "Reply"; public static final String MESSAGE_LABEL = "Message"; + + private int delayMillis = 300000; //5 minutes by default (is read from a configuration file in the first async callback) - private int delayMillis = 300000; //5 minutes by default + private int currNewUpdatesNo = 0; private boolean isFirstTweet = false; @@ -82,11 +88,16 @@ public class NewsFeedPanel extends Composite { private UserInfo myUserInfo; private FilterType currentFilter; private Timer feedsTimer; + + private ArrayList allUpdates = new ArrayList(); + + private ArrayList tempCacheNewUpdates = new ArrayList(); + /** * events binder */ private void bind() { - + eventBus.addHandler(StopTimerEvent.TYPE, new StopTimerEventHandler() { @Override public void onStopTimer(StopTimerEvent event) { @@ -164,6 +175,7 @@ public class NewsFeedPanel extends Composite { public NewsFeedPanel() { bind(); mainPanel.add(filterPanel); + mainPanel.add(newUpdatesPanel); mainPanel.add(newsPanel); filterPanel.add(new FilterPanel(this, newsService)); @@ -194,16 +206,16 @@ public class NewsFeedPanel extends Composite { } } }); - + feedsTimer = new Timer() { @Override public void run() { - refreshFeeds(); + checkForNewUpdates(); } }; feedsTimer.scheduleRepeating(delayMillis); } - + private void resetTimer() { feedsTimer.cancel(); feedsTimer.scheduleRepeating(delayMillis); @@ -214,10 +226,10 @@ public class NewsFeedPanel extends Composite { /** * */ - private void refreshFeeds() { + private void checkForNewUpdates() { switch (currentFilter) { case ALL_UPDATES: - showAllUpdatesFeeds(); + checkAllUpdatesFeeds(); break; case CONNECTIONS: showOnlyConnectionsFeeds(); @@ -227,6 +239,43 @@ public class NewsFeedPanel extends Composite { break; } } + //TODO: finish this + private void checkAllUpdatesFeeds() { + newsService.getAllUpdateUserFeeds(new AsyncCallback>() { + @Override + public void onSuccess(ArrayList feeds) { + if (feeds != null && allUpdates.size() > 0) { + + Date myLastUpdateTime = allUpdates.get(0).getFeed().getTime(); //this is the last update in the View + + tempCacheNewUpdates = new ArrayList(); //need to reset it everytime i check (in case someone deleted the updated in the meanwhile) + + //check if there are new updates (enter the while) and put them in a temporary cache for displaying on user click + + int i = 0; + while (i < feeds.size() && feeds.get(i).getFeed().getTime().after(myLastUpdateTime)) { + tempCacheNewUpdates.add(feeds.get(i)); + i++; + } + + /* currNewUpdatesNo keeps the number of updates to be added on user clicks, + * i keeps the total number as it arrives, + * if they differ you got to refresh the updates to show the new number + */ + if (currNewUpdatesNo < i) { + newUpdatesPanel.clear(); //remove the current show update button if present + newUpdatesPanel.add(new NewFeedsAvailable(i)); + currNewUpdatesNo = i; + } + } + } + @Override + public void onFailure(Throwable caught) {} + }); + } + + + /** * All Updates */ @@ -249,8 +298,10 @@ public class NewsFeedPanel extends Composite { newsPanel.setHeight(""); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); - for (EnhancedFeed feed : feeds) + for (EnhancedFeed feed : feeds) { newsPanel.add(new TweetTemplate(myUserInfo, feed, eventBus)); + allUpdates.add(feed); + } if (feeds.size() < 5) { newsPanel.add(new Image(spacer)); } @@ -271,7 +322,7 @@ public class NewsFeedPanel extends Composite { } }); } - + /** * Only User Connections */ @@ -393,7 +444,7 @@ public class NewsFeedPanel extends Composite { } }); } - + /** * used when addin directly a feed from the UI (IPC) * @param userid @@ -406,7 +457,7 @@ public class NewsFeedPanel extends Composite { cFeed.getDescription(), PrivacyLevel.CONNECTION, cFeed.getFullName(), cFeed.getEmail(), cFeed.getThumbnailURL(), cFeed.getLinkTitle(), cFeed.getLinkDescription(), cFeed.getLinkHost()); EnhancedFeed toAdd = new EnhancedFeed(feed, false, true); //false cuz he could not have liked this yet and true because is the current user's - + final TweetTemplate tt = new TweetTemplate(myUserInfo, toAdd, eventBus, true); if (isFirstTweet) { newsPanel.clear(); @@ -434,7 +485,7 @@ public class NewsFeedPanel extends Composite { newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); newsPanel.add(loadingImage); } - + private void showProblems() { newsPanel.clear(); newsPanel.add(new HTML("
" + @@ -475,7 +526,7 @@ public class NewsFeedPanel extends Composite { Window.alert("Could not load this component: " + reason.getMessage()); } }); - + } private void doAddComment(final TweetTemplate owner, String text) { diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/NewFeedsAvailable.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/NewFeedsAvailable.java new file mode 100644 index 0000000..a17fd23 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/NewFeedsAvailable.java @@ -0,0 +1,36 @@ +package org.gcube.portlets.user.newsfeed.client.templates; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.Widget; + +public class NewFeedsAvailable extends Composite { + + private static NewFeedsAvailableUiBinder uiBinder = GWT + .create(NewFeedsAvailableUiBinder.class); + + interface NewFeedsAvailableUiBinder extends + UiBinder { + } + @UiField HTML caption; + + public NewFeedsAvailable(int newUpdatesNo) { + initWidget(uiBinder.createAndBindUi(this)); + if (newUpdatesNo > 0) { + caption.setHTML(newUpdatesNo > 1 ? "See " + newUpdatesNo + " new Updates" : "See 1 new Update"); + //create the fade transition effect + Timer t = new Timer() { + @Override + public void run() { + caption.addStyleName("new-feeds-show"); + } + }; + t.schedule(100); + } + else throw new IllegalArgumentException("newUpdatesNo must be greater than 0"); + } +} diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/NewFeedsAvailable.ui.xml b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/NewFeedsAvailable.ui.xml new file mode 100644 index 0000000..1d80784 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/NewFeedsAvailable.ui.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/server/NewsServiceImpl.java b/src/main/java/org/gcube/portlets/user/newsfeed/server/NewsServiceImpl.java index eac8401..13dd7c9 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/server/NewsServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/server/NewsServiceImpl.java @@ -61,6 +61,11 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService * */ private static final String SESSION_ADMIN_ATTR = "SESSION_ADMIN_ATTR"; + + /** + * + */ + private static final String USER_SETTINGS_ATTR = "USER_SETTINGS_ATTR"; private DatabookStore store; @@ -238,28 +243,28 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService ArrayList toMerge = new ArrayList(); HashMap feedsMap = new HashMap(); - ArrayList OrganizationFeeds = (ArrayList) store.getRecentFeedsByVRE("/gcube/devsec/devVRE", 10); + ArrayList OrganizationFeeds = (ArrayList) store.getRecentFeedsByVRE("/gcube/devsec/devVRE", 5); for (Feed feed : OrganizationFeeds) { feedsMap.put(feed.getKey(), feed); } - if (! onlyConnections) { - //User Own Feeds - ArrayList userFeeds = (ArrayList) store.getRecentFeedsByUser(userName, 10); - for (Feed feed : userFeeds) - feedsMap.put(feed.getKey(), feed); - // //Portal Feeds - ArrayList portalFeeds = (ArrayList) store.getAllPortalPrivacyLevelFeeds(); - for (Feed feed : portalFeeds) - feedsMap.put(feed.getKey(), feed); - } - //UserFriends Feeds - ArrayList userFriendsIds = (ArrayList)store.getFriends(userName); - for (String userid : userFriendsIds) { - for (Feed feed : store.getRecentFeedsByUser(userid, 10)) { - feedsMap.put(feed.getKey(), feed); - } - } +// if (! onlyConnections) { +// //User Own Feeds +// ArrayList userFeeds = (ArrayList) store.getRecentFeedsByUser(userName, 10); +// for (Feed feed : userFeeds) +// feedsMap.put(feed.getKey(), feed); +// // //Portal Feeds +// ArrayList portalFeeds = (ArrayList) store.getAllPortalPrivacyLevelFeeds(); +// for (Feed feed : portalFeeds) +// feedsMap.put(feed.getKey(), feed); +// } +// //UserFriends Feeds +// ArrayList userFriendsIds = (ArrayList)store.getFriends(userName); +// for (String userid : userFriendsIds) { +// for (Feed feed : store.getRecentFeedsByUser(userid, 10)) { +// feedsMap.put(feed.getKey(), feed); +// } +// } for (String key: feedsMap.keySet()) { toMerge.add(feedsMap.get(key)); } @@ -451,8 +456,8 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService @Override public UserSettings getUserSettings() { - if (getUserFromSession() != null) - return getUserFromSession(); + if (getUserSettingsFromSession() != null) + return getUserSettingsFromSession(); try { String username = getASLSession().getUsername(); String email = username+"@isti.cnr.it"; @@ -469,7 +474,7 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService UserInfo userInfo = new UserInfo(username, fullName, thumbnailURL, user.getEmailAddress(), accountURL, true, false, null); UserSettings toReturn = new UserSettings(userInfo, getFeedsRefreshTimeInMillis()); - setUserInSession(toReturn); + setUserSettingsInSession(toReturn); return toReturn; } else { @@ -525,12 +530,12 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService } } - private UserSettings getUserFromSession() { - return (UserSettings) getASLSession().getAttribute(UserInfo.USER_INFO_ATTR); + private UserSettings getUserSettingsFromSession() { + return (UserSettings) getASLSession().getAttribute(USER_SETTINGS_ATTR); } - private void setUserInSession(UserSettings user) { - getASLSession().setAttribute(UserInfo.USER_INFO_ATTR, user); + private void setUserSettingsInSession(UserSettings user) { + getASLSession().setAttribute(USER_SETTINGS_ATTR, user); } /** * tell if a feed is belonging to the current user or not @@ -631,31 +636,34 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService * @return the refreshingTime in milliseconds */ private int getFeedsRefreshTimeInMillis() { - Properties props = new Properties(); - int toReturn = 0; - int minutes = 0; - try { - String propertyfile = this.getThreadLocalRequest().getServletPath()+"conf/settings.properties"; - File propsFile = new File(propertyfile); - FileInputStream fis = new FileInputStream(propsFile); - props.load( fis); - - minutes = Integer.parseInt(props.getProperty("REFRESH_TIME")); - toReturn = minutes*60*1000; - } - //catch exception in case properties file does not exist - catch(IOException e) { - toReturn = 300000; //5 minutes - _log.error("settings.properties file not found under conf dir, returning 5 minutes"); - return toReturn; - } - //catch exception in case the property value isNot a Number - catch (ClassCastException ex) { - toReturn = 300000; //5 minutes - _log.error("REFRESH_TIME must be a number (in minutes) returning 5 minutes"); - return toReturn; - } - _log.debug("Returning REFRESH_TIME in millis: " + toReturn + " minutes: " + minutes); - return toReturn; + return 15000; + //TODO: +// Properties props = new Properties(); +// int toReturn = 0; +// int minutes = 0; +// String propertyfile = ""; +// try { +// propertyfile = this.getThreadLocalRequest().getContextPath()+"conf/settings.properties"; +// File propsFile = new File(propertyfile); +// FileInputStream fis = new FileInputStream(propsFile); +// props.load( fis); +// +// minutes = Integer.parseInt(props.getProperty("REFRESH_TIME")); +// toReturn = minutes*60*1000; +// } +// //catch exception in case properties file does not exist +// catch(IOException e) { +// toReturn = 300000; //5 minutes +// _log.error("settings.properties file not found under " + propertyfile +", returning 5 minutes"); +// return toReturn; +// } +// //catch exception in case the property value isNot a Number +// catch (ClassCastException ex) { +// toReturn = 300000; //5 minutes +// _log.error("REFRESH_TIME must be a number (in minutes) returning 5 minutes"); +// return toReturn; +// } +// _log.debug("Returning REFRESH_TIME in millis: " + toReturn + ", (" + minutes + " minutes)"); +// return toReturn; } } diff --git a/src/main/webapp/NewsFeed.css b/src/main/webapp/NewsFeed.css index 1062aaa..fc78495 100644 --- a/src/main/webapp/NewsFeed.css +++ b/src/main/webapp/NewsFeed.css @@ -1,11 +1,56 @@ @import url(http://fonts.googleapis.com/css?family=Architects+Daughter); -/* FILTER Widget*/ table { border-collapse: separate !important; border-spacing: 0; } +.new-feeds-container { + position: relative; +} + +.new-feeds-available { + color: #444; + font-family: 'Lucida Grande', Verdana, 'Bitstream Vera Sans', Arial, + sans-serif; + text-align: center; + font-size: 13px; + width: 576px; + margin: 0px 25px 0px 8px; + padding: 3px; + border: 1px solid #75AAD0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + height: 0px; + opacity: 0; + transition-property: opacity, height; + transition-duration: .40s; + transition-timing-function: ease-out; + -moz-transition-property: opacity, height; + -moz-transition-duration: .40s; + -moz-transition-timing-function: ease-out; + -webkit-transition-property: opacity, height; + -webkit-transition-duration: .40s; + -webkit-transition-timing-function: ease-out; + -ms-transition-property: opacity, height; + -ms-transition-duration: .40s; + -ms-transition-timing-function: ease-out; +} + +.new-feeds-show { + opacity: 1; + background: #D6E2FC; + height: 18px; +} + +.new-feeds-available:hover { + background: #EDEFF4; + cursor: pointer; + cursor: hand; + text-decoration: underline; +} + .nofeed-message { line-height: 40px; font-family: 'Architects Daughter', arial, sans-serif;