diff --git a/.classpath b/.classpath index 053acfd..e9be3e2 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,6 @@ - + @@ -30,5 +30,5 @@ - + diff --git a/.settings/com.google.gdt.eclipse.core.prefs b/.settings/com.google.gdt.eclipse.core.prefs index 9eaf71a..a57e1f4 100644 --- a/.settings/com.google.gdt.eclipse.core.prefs +++ b/.settings/com.google.gdt.eclipse.core.prefs @@ -1,5 +1,5 @@ eclipse.preferences.version=1 jarsExcludedFromWebInfLib= -lastWarOutDir=/Users/massi/Documents/workspace/notifications/target/notifications-1.1.0-SNAPSHOT +lastWarOutDir=/Users/massi/Documents/workspace/notifications/target/notifications-1.2.0-SNAPSHOT warSrcDir=src/main/webapp warSrcDirIsOutput=false diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index 505c604..2c15b14 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,13 +1,9 @@ - - + - - uses - diff --git a/pom.xml b/pom.xml index da1a781..283906e 100644 --- a/pom.xml +++ b/pom.xml @@ -13,14 +13,13 @@ org.gcube.portlets.user notifications war - 1.1.0-SNAPSHOT + 1.2.0-SNAPSHOT gCube Notifications Portlet 2.5.1 distro - 1.7 1.7 ${project.build.directory}/${project.build.finalName} @@ -52,7 +51,7 @@ com.google.gwt gwt-user provided - + com.google.gwt gwt-servlet @@ -72,6 +71,12 @@ switch-button-widget [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT) + + org.gcube.portal + social-networking-library + [1.3.0-SNAPSHOT, 2.0.0-SNAPSHOT) + provided + org.gcube.portal custom-portal-handler @@ -101,18 +106,6 @@ portlet-api provided - - org.gcube.portal - social-networking-library - [1.3.0-SNAPSHOT, 2.0.0-SNAPSHOT) - provided - - - junit - junit - 4.7 - test - diff --git a/src/main/java/org/gcube/portlets/user/notifications/client/NotificationsService.java b/src/main/java/org/gcube/portlets/user/notifications/client/NotificationsService.java index 2db7a34..88149eb 100644 --- a/src/main/java/org/gcube/portlets/user/notifications/client/NotificationsService.java +++ b/src/main/java/org/gcube/portlets/user/notifications/client/NotificationsService.java @@ -5,7 +5,6 @@ import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; -import java.util.TreeMap; import org.gcube.portal.databook.shared.Notification; import org.gcube.portal.databook.shared.NotificationChannelType; @@ -24,6 +23,8 @@ public interface NotificationsService extends RemoteService { UserInfo getUserInfo(); HashMap> getUserNotifications(); + HashMap> getUserNotificationsByRange(int from, int quantity); + boolean setAllUserNotificationsRead(); LinkedHashMap> getUserNotificationPreferences(); diff --git a/src/main/java/org/gcube/portlets/user/notifications/client/NotificationsServiceAsync.java b/src/main/java/org/gcube/portlets/user/notifications/client/NotificationsServiceAsync.java index 75a811a..a964503 100644 --- a/src/main/java/org/gcube/portlets/user/notifications/client/NotificationsServiceAsync.java +++ b/src/main/java/org/gcube/portlets/user/notifications/client/NotificationsServiceAsync.java @@ -30,6 +30,7 @@ public interface NotificationsServiceAsync { Map enabledChannels, AsyncCallback callback); - + void getUserNotificationsByRange(int from, int quantity, + AsyncCallback>> callback); } diff --git a/src/main/java/org/gcube/portlets/user/notifications/client/view/NotificationsPanel.java b/src/main/java/org/gcube/portlets/user/notifications/client/view/NotificationsPanel.java index bfc3d29..0e6bbaf 100644 --- a/src/main/java/org/gcube/portlets/user/notifications/client/view/NotificationsPanel.java +++ b/src/main/java/org/gcube/portlets/user/notifications/client/view/NotificationsPanel.java @@ -5,17 +5,15 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.TreeMap; - import org.gcube.portal.databook.shared.Notification; -import org.gcube.portal.databook.shared.NotificationChannelType; -import org.gcube.portal.databook.shared.NotificationType; import org.gcube.portal.databook.shared.UserInfo; import org.gcube.portlets.user.notifications.client.NotificationsService; import org.gcube.portlets.user.notifications.client.NotificationsServiceAsync; import org.gcube.portlets.user.notifications.client.view.templates.DayWrapper; +import org.gcube.portlets.user.notifications.client.view.templates.ShowMoreNotifications; import org.gcube.portlets.user.notifications.client.view.templates.SingleNotificationView; +import org.gcube.portlets.user.notifications.shared.NotificationConstants; import org.gcube.portlets.user.notifications.shared.NotificationPreference; import com.google.gwt.core.client.GWT; @@ -25,6 +23,8 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.Window.ScrollEvent; +import com.google.gwt.user.client.Window.ScrollHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTML; @@ -33,8 +33,8 @@ import com.google.gwt.user.client.ui.HasHorizontalAlignment; 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; +import com.google.gwt.user.client.ui.Widget; /** * @author Massimiliano Assante ISTI-CNR @@ -51,10 +51,13 @@ public class NotificationsPanel extends Composite { private static final String warning = GWT.getModuleBaseURL() + "../images/warning_blue.png"; private UserInfo myUserInfo; private Image loadingImage; + private ShowMoreNotifications showMoreWidget; + //needed to know the next range start + private int fromStartingPoint = 0; private VerticalPanel container = new VerticalPanel(); private HorizontalPanel settingsPanel = new HorizontalPanel(); - + private VerticalPanel showMoreNotificationsPanel = new VerticalPanel(); private VerticalPanel loadingPanel = new VerticalPanel(); private VerticalPanel mainPanel; @@ -67,6 +70,7 @@ public class NotificationsPanel extends Composite { mainPanel.setWidth("100%"); container.setWidth("100%"); settingsPanel.setWidth("100%"); + showMoreNotificationsPanel.setWidth("100%"); settingsPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); settingsPanel.add(notificationSettings); container.add(settingsPanel); @@ -110,6 +114,17 @@ public class NotificationsPanel extends Composite { }); } }); + + //this is for the automatic scroll of feeds + Window.addWindowScrollHandler(new ScrollHandler() { + @Override + public void onWindowScroll(ScrollEvent event) { + boolean isInView = isScrolledIntoView(showMoreWidget); + if (isInView) { + doShowMoreNotifications(); + } + } + }); } @@ -154,6 +169,15 @@ public class NotificationsPanel extends Composite { } if (notCounter > 5 && notCounter < 10) mainPanel.add(new Image(spacer)); + + //if you are showing more than NotificationConstants.NOTIFICATION_NUMBER + if (notCounter >= NotificationConstants.NOTIFICATION_NUMBER) { + GWT.log("Show MORE "); + showMoreNotificationsPanel.setHorizontalAlignment(HasAlignment.ALIGN_CENTER); + showMoreWidget = new ShowMoreNotifications(); + showMoreNotificationsPanel.add(showMoreWidget); + mainPanel.add(showMoreNotificationsPanel); + } } } else @@ -162,6 +186,70 @@ public class NotificationsPanel extends Composite { }); } + /** + * called when a user scroll down the page to the bottom + */ + private void doShowMoreNotifications() { + showMoreNotificationsPanel.remove(0); + loadingImage.getElement().getStyle().setMargin(10, Unit.PX); + showMoreNotificationsPanel.add(loadingImage); + int from = (fromStartingPoint == 0) ? NotificationConstants.NOTIFICATION_NUMBER+1 : fromStartingPoint; + fromStartingPoint = from; + final int quantity = 20; + GWT.log("StartingPoint = " + from); + + notificationService.getUserNotificationsByRange(from, quantity, new AsyncCallback>>() { + @Override + public void onSuccess(HashMap> notificationsPerDay) { + mainPanel.remove(showMoreNotificationsPanel); + if (notificationsPerDay != null) { + ArrayList sortedKeys=new ArrayList(notificationsPerDay.keySet()); + Collections.sort(sortedKeys, Collections.reverseOrder()); + + int notCounter = 0; + for (Date day : sortedKeys) { + mainPanel.add(new DayWrapper(day)); + for (Notification notif : notificationsPerDay.get(day)) { + mainPanel.add(new SingleNotificationView(notif)); + notCounter++; + } + } + fromStartingPoint += notCounter; + GWT.log("StartingPoint incremented = " + fromStartingPoint); + if (notCounter >= quantity) { //there could be more notifications + GWT.log("Show MORE "); + showMoreNotificationsPanel.setHorizontalAlignment(HasAlignment.ALIGN_CENTER); + showMoreWidget = new ShowMoreNotifications(); + showMoreNotificationsPanel.add(showMoreWidget); + mainPanel.add(showMoreNotificationsPanel); + } + } + } + @Override + public void onFailure(Throwable caught) { + showMoreNotificationsPanel.clear(); + mainPanel.add(new HTML("
" + + "Ops! There were problems while retrieving your Notifications!.
" + + "Please try again in a short while.
")); + } + }); + } + + /** + * @param widget the widget to check + * @returnn true if the widget is in the visible part of the page + */ + private boolean isScrolledIntoView(Widget widget) { + if (widget != null) { + int docViewTop = Window.getScrollTop(); + int docViewBottom = docViewTop + Window.getClientHeight(); + int elemTop = widget.getAbsoluteTop(); + int elemBottom = elemTop + widget.getOffsetHeight(); + return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); + } + return false; + } + private void showLoader() { mainPanel.clear(); mainPanel.setWidth("100%"); diff --git a/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/ShowMoreNotifications.java b/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/ShowMoreNotifications.java new file mode 100644 index 0000000..0335678 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/ShowMoreNotifications.java @@ -0,0 +1,42 @@ +package org.gcube.portlets.user.notifications.client.view.templates; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.dom.client.Style.Visibility; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.Widget; + +public class ShowMoreNotifications extends Composite { + + private static ShowMoreNotificationsUiBinder uiBinder = GWT + .create(ShowMoreNotificationsUiBinder.class); + + interface ShowMoreNotificationsUiBinder extends UiBinder { + } + + + @UiField HTML caption; + @UiField HTMLPanel panel; + + + public ShowMoreNotifications() { + initWidget(uiBinder.createAndBindUi(this)); + panel.getElement().getStyle().setMarginTop(10, Unit.PX); + caption.addStyleName("new-notifications-show"); + caption.getElement().getStyle().setBackgroundColor("transparent"); + caption.getElement().getStyle().setFontSize(14, Unit.PX); + caption.setHTML("Show more notifications"); + //hiding as not needed anymore (the user click) + panel.getElement().getStyle().setVisibility(Visibility.HIDDEN); + } + + @UiHandler("caption") + void onClick(ClickEvent e) { + } +} diff --git a/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/ShowMoreNotifications.ui.xml b/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/ShowMoreNotifications.ui.xml new file mode 100644 index 0000000..743c429 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/ShowMoreNotifications.ui.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/SingleNotificationView.java b/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/SingleNotificationView.java index 3961d1c..dd639c0 100644 --- a/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/SingleNotificationView.java +++ b/src/main/java/org/gcube/portlets/user/notifications/client/view/templates/SingleNotificationView.java @@ -1,5 +1,6 @@ package org.gcube.portlets.user.notifications.client.view.templates; +import org.apache.cassandra.cli.CliParser.attr_name_return; import org.gcube.portal.databook.client.GCubeSocialNetworking; import org.gcube.portal.databook.client.util.Encoder; import org.gcube.portal.databook.shared.Notification; @@ -60,6 +61,8 @@ public class SingleNotificationView extends Composite { actualHTML = actualHTML.replace("link.", "link"); actualHTML += " you shared."; } + //shorten the notification text if greather than 200 chars + actualHTML = actualHTML.length() > 200 ? actualHTML.substring(0, 200) + " ..." : actualHTML; notificationText.setHTML( ""+ toShow.getSenderFullName()+" " + actualHTML); + timeArea.setHTML(DateTimeFormat.getFormat("h:mm a").format(toShow.getTime())); notificationImage.setResource(getImageType(toShow.getType())); diff --git a/src/main/java/org/gcube/portlets/user/notifications/server/NotificationsServiceImpl.java b/src/main/java/org/gcube/portlets/user/notifications/server/NotificationsServiceImpl.java index 2dcc47a..f370ae3 100644 --- a/src/main/java/org/gcube/portlets/user/notifications/server/NotificationsServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/notifications/server/NotificationsServiceImpl.java @@ -26,6 +26,7 @@ import org.gcube.portal.databook.shared.NotificationChannelType; import org.gcube.portal.databook.shared.NotificationType; import org.gcube.portal.databook.shared.UserInfo; import org.gcube.portlets.user.notifications.client.NotificationsService; +import org.gcube.portlets.user.notifications.shared.NotificationConstants; import org.gcube.portlets.user.notifications.shared.NotificationPreference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,7 +75,7 @@ public class NotificationsServiceImpl extends RemoteServiceServlet implements No String user = (String) this.getThreadLocalRequest().getSession().getAttribute(ScopeHelper.USERNAME_ATTRIBUTE); if (user == null) { user = "test.user"; -// user = "massimiliano.assante"; + user = "massimiliano.assante"; _log.warn("USER IS NULL setting "+user+" and Running OUTSIDE PORTAL"); withinPortal = false; @@ -115,12 +116,12 @@ public class NotificationsServiceImpl extends RemoteServiceServlet implements No } /** - * returns the notifications separated per days + * returns the notifications separated per day */ public HashMap> getUserNotifications() { HashMap> toReturn = new HashMap>(); try { - for (Notification notification : store.getAllNotificationByUser(getASLSession().getUsername(), 70)) { + for (Notification notification : store.getAllNotificationByUser(getASLSession().getUsername(), NotificationConstants.NOTIFICATION_NUMBER)) { Date dateWithoutTime = removeTimePart(notification.getTime()); if (! toReturn.containsKey(dateWithoutTime)) { ArrayList nots = new ArrayList(); @@ -137,6 +138,31 @@ public class NotificationsServiceImpl extends RemoteServiceServlet implements No } return toReturn; } + + /** + * returns the notifications in the range separated per day + */ + public HashMap> getUserNotificationsByRange(int from, int quantity) { + HashMap> toReturn = new HashMap>(); + try { + for (Notification notification : store.getRangeNotificationsByUser(getASLSession().getUsername(), from, quantity)) { + Date dateWithoutTime = removeTimePart(notification.getTime()); + if (! toReturn.containsKey(dateWithoutTime)) { + ArrayList nots = new ArrayList(); + nots.add(notification); + toReturn.put(dateWithoutTime, nots); + } else { + toReturn.get(dateWithoutTime).add(notification); + } + } + + } catch (Exception e) { + _log.error("While trying to get User notifications"); + e.printStackTrace(); + } + return toReturn; + } + /** * we want notification split per day * @param date @@ -176,10 +202,10 @@ public class NotificationsServiceImpl extends RemoteServiceServlet implements No Properties descriptions = getDescriptionsByType(); TreeMap> treeMap = new TreeMap>(); - + try { Map storePreferences = store.getUserNotificationPreferences(userid); - + for (NotificationType type : storePreferences.keySet()) { String category = categories.getProperty(type.toString()); String typeLabel = labels.getProperty(type.toString()); diff --git a/src/main/java/org/gcube/portlets/user/notifications/shared/NotificationConstants.java b/src/main/java/org/gcube/portlets/user/notifications/shared/NotificationConstants.java new file mode 100644 index 0000000..fef904c --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/notifications/shared/NotificationConstants.java @@ -0,0 +1,5 @@ +package org.gcube.portlets.user.notifications.shared; + +public class NotificationConstants { + public final static int NOTIFICATION_NUMBER = 70; +} diff --git a/src/main/resources/org/gcube/portlets/user/notifications/Notifications.gwt.xml b/src/main/resources/org/gcube/portlets/user/notifications/Notifications.gwt.xml index c48e90f..5471073 100644 --- a/src/main/resources/org/gcube/portlets/user/notifications/Notifications.gwt.xml +++ b/src/main/resources/org/gcube/portlets/user/notifications/Notifications.gwt.xml @@ -2,10 +2,6 @@ - - - - diff --git a/src/main/webapp/Notifications.css b/src/main/webapp/Notifications.css index e0072d4..d4fb6af 100644 --- a/src/main/webapp/Notifications.css +++ b/src/main/webapp/Notifications.css @@ -51,6 +51,13 @@ a.link:hover { text-decoration: underline; } +.new-notifications-show { + opacity: 1; + background: #D6E2FC; + height: 18px; +} + + .day-wrapper { width: 100%; border-bottom-color: #DADADA; diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index d45685e..ee7748f 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -20,20 +20,6 @@ /org.gcube.portlets.user.notifications.NotificationsJUnit/notifications/notificationsServlet - - jUnitHostImpl - com.google.gwt.junit.server.JUnitHostImpl - - - jUnitHostImpl - /org.gcube.portlets.user.notifications.NotificationsJUnit/junithost/* - - - - jUnitHostImpl - /notifications/junithost/* - - Notifications.html diff --git a/src/test/java/org/gcube/portlets/user/notifications/client/GwtTestNotifications.java b/src/test/java/org/gcube/portlets/user/notifications/client/GwtTestNotifications.java deleted file mode 100644 index b9ffc54..0000000 --- a/src/test/java/org/gcube/portlets/user/notifications/client/GwtTestNotifications.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.gcube.portlets.user.notifications.client; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.junit.client.GWTTestCase; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.gwt.user.client.rpc.ServiceDefTarget; - -/** - * GWT JUnit integration tests must extend GWTTestCase. - * Using "GwtTest*" naming pattern exclude them from running with - * surefire during the test phase. - * - * If you run the tests using the Maven command line, you will have to - * navigate with your browser to a specific url given by Maven. - * See http://mojo.codehaus.org/gwt-maven-plugin/user-guide/testing.html - * for details. - */ -public class GwtTestNotifications extends GWTTestCase { - - /** - * Must refer to a valid module that sources this class. - */ - public String getModuleName() { - return "org.gcube.portlets.user.notifications.NotificationsJUnit"; - } - - /** - * Tests the FieldVerifier. - */ - public void testFieldVerifier() { -// assertFalse(FieldVerifier.isValidName(null)); -// assertFalse(FieldVerifier.isValidName("")); -// assertFalse(FieldVerifier.isValidName("a")); -// assertFalse(FieldVerifier.isValidName("ab")); -// assertFalse(FieldVerifier.isValidName("abc")); -// assertTrue(FieldVerifier.isValidName("abcd")); - } - - /** - * This test will send a request to the server using the greetServer method in - * NotificationsService and verify the response. - */ - public void testGreetingService() { -// // Create the service that we will test. -// NotificationsServiceAsync greetingService = GWT.create(NotificationsService.class); -// ServiceDefTarget target = (ServiceDefTarget) greetingService; -// target.setServiceEntryPoint(GWT.getModuleBaseURL() + "Notifications/greet"); - - // Since RPC calls are asynchronous, we will need to wait for a response - // after this test method returns. This line tells the test runner to wait - // up to 10 seconds before timing out. - // delayTestFinish(10000); - -// // Send a request to the server. -// greetingService.greetServer("GWT User", new AsyncCallback() { -// public void onFailure(Throwable caught) { -// // The request resulted in an unexpected error. -// fail("Request failure: " + caught.getMessage()); -// } -// -// public void onSuccess(String result) { -// // Verify that the response is correct. -// assertTrue(result.startsWith("Hello, GWT User!")); -// -// // Now that we have received a response, we need to tell the test runner -// // that the test is complete. You must call finishTest() after an -// // asynchronous test finishes successfully, or the test will time out. -// finishTest(); -// } -// }); - } - - -}