Commit e38f54e9 authored by Evan W. Patton's avatar Evan W. Patton

Defer gallery loading until user chooses to open it

Daily we have 750,000+ requests for resources via /ode/gallery. These
requests occur even if the user never actually accesses the gallery
since they are done at initialization of Ode. This commit defers the
initialization of the gallery UI so that it is only generated once the
user accesses the gallery.

Change-Id: Ic16ae5f45c8f79570d763408f5958170fa332ae1
parent f20f55c7
......@@ -9,6 +9,7 @@ package com.google.appinventor.client;
import static com.google.appinventor.client.Ode.MESSAGES;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.appinventor.client.explorer.project.Project;
......@@ -77,14 +78,21 @@ public class GalleryClient {
listeners.add(listener);
}
/**
* Remove a listener from the listeners list
* @param listener gallery request listener
*/
public void removeListener(GalleryRequestListener listener) {
listeners.remove(listener);
}
/**
* Returns the gallery settings.
*
* @return gallery settings
*/
public GallerySettings getGallerySettings() {
final Ode ode = Ode.getInstance();
return ode.getGallerySettings();
return Ode.getGallerySettings();
}
/**
......@@ -103,8 +111,10 @@ public class GalleryClient {
@Override
public void onSuccess(GalleryAppListResult appsResult) {
// the server has returned us something
for (GalleryRequestListener listener:listeners) {
listener.onAppListRequestCompleted(appsResult, REQUEST_SEARCH, refreshable);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onAppListRequestCompleted(appsResult, REQUEST_SEARCH, refreshable)) {
i.remove();
}
}
}
};
......@@ -127,8 +137,10 @@ public class GalleryClient {
@Override
public void onSuccess(GalleryAppListResult appsResult) {
// the server has returned us something
for (GalleryRequestListener listener:listeners) {
listener.onAppListRequestCompleted(appsResult, REQUEST_BYDEVELOPER, false);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onAppListRequestCompleted(appsResult, REQUEST_BYDEVELOPER, false)) {
i.remove();
}
}
}
};
......@@ -150,8 +162,10 @@ public class GalleryClient {
@Override
public void onSuccess(GalleryAppListResult appsResult) {
// the server has returned us something
for (GalleryRequestListener listener:listeners) {
listener.onAppListRequestCompleted(appsResult, REQUEST_FEATURED, refreshable);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onAppListRequestCompleted(appsResult, REQUEST_FEATURED, false)) {
i.remove();
}
}
}
};
......@@ -173,8 +187,10 @@ public class GalleryClient {
@Override
public void onSuccess(GalleryAppListResult appsResult) {
// the server has returned us something
for (GalleryRequestListener listener:listeners) {
listener.onAppListRequestCompleted(appsResult, REQUEST_TUTORIAL, refreshable);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onAppListRequestCompleted(appsResult, REQUEST_TUTORIAL, false)) {
i.remove();
}
}
}
};
......@@ -195,8 +211,10 @@ public class GalleryClient {
@Override
public void onSuccess(GalleryAppListResult appsResult) {
// the server has returned us something
for (GalleryRequestListener listener:listeners) {
listener.onAppListRequestCompleted(appsResult, REQUEST_RECENT, refreshable);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onAppListRequestCompleted(appsResult, REQUEST_RECENT, false)) {
i.remove();
}
}
}
};
......@@ -217,8 +235,10 @@ public class GalleryClient {
@Override
public void onSuccess(GalleryAppListResult appsResult) {
// the server has returned us something
for (GalleryRequestListener listener:listeners) {
listener.onAppListRequestCompleted(appsResult, REQUEST_MOSTLIKED, refreshable);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onAppListRequestCompleted(appsResult, REQUEST_MOSTLIKED, false)) {
i.remove();
}
}
}
};
......@@ -240,8 +260,10 @@ public class GalleryClient {
@Override
public void onSuccess(GalleryAppListResult appsResult) {
// the server has returned us something
for (GalleryRequestListener listener:listeners) {
listener.onAppListRequestCompleted(appsResult, REQUEST_MOSTDOWNLOADED, refreshable);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onAppListRequestCompleted(appsResult, REQUEST_MOSTDOWNLOADED, false)) {
i.remove();
}
}
}
};
......@@ -253,8 +275,10 @@ public class GalleryClient {
* GetRemixedToList gets children list that apps remixed to then tells listeners
*/
public void GetRemixedToList(GalleryAppListResult appsResult) {
for (GalleryRequestListener listener:listeners) {
listener.onAppListRequestCompleted(appsResult, REQUEST_REMIXED_TO, true);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onAppListRequestCompleted(appsResult, REQUEST_REMIXED_TO, true)) {
i.remove();
}
}
}
......@@ -279,8 +303,10 @@ public class GalleryClient {
@Override
public void onSuccess(List<GalleryComment> comments) {
// now relay the result back to UI client
for (GalleryRequestListener listener:listeners) {
listener.onCommentsRequestCompleted(comments);
for (Iterator<GalleryRequestListener> i = listeners.iterator(); i.hasNext();) {
if (i.next().onCommentsRequestCompleted(comments)) {
i.remove();
}
}
}
};
......
......@@ -11,10 +11,7 @@ import java.util.List;
import com.google.appinventor.client.explorer.youngandroid.GalleryPage;
import com.google.appinventor.shared.rpc.project.GalleryApp;
import com.google.appinventor.shared.rpc.project.GalleryAppListResult;
import com.google.appinventor.shared.rpc.project.GalleryComment;
import com.google.appinventor.shared.rpc.project.UserProject;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.ErrorEvent;
......@@ -26,10 +23,10 @@ import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TabPanel;
public class GalleryGuiFactory implements GalleryRequestListener {
GalleryClient gallery = null;
public class GalleryGuiFactory {
GalleryClient gallery = GalleryClient.getInstance();
public static final OdeMessages MESSAGES = GWT.create(OdeMessages.class);
public static final OdeMessages MESSAGES = Ode.getMessages();
private final String PERSON_URL = "/images/person.png";
private final String HOLLOW_HEART_ICON_URL = "/images/numLikeHollow.png";
......@@ -42,8 +39,6 @@ public class GalleryGuiFactory implements GalleryRequestListener {
* Generates a new GalleryGuiFactory instance.
*/
public GalleryGuiFactory() {
gallery = GalleryClient.getInstance();
gallery.addListener(this);
}
/**
......@@ -344,19 +339,4 @@ public class GalleryGuiFactory implements GalleryRequestListener {
}
}
@Override
public void onAppListRequestCompleted(GalleryAppListResult appsResult, int requestID, boolean refreshable) {
// TODO Auto-generated method stub
}
@Override
public void onCommentsRequestCompleted(List<GalleryComment> comments) {
// TODO Auto-generated method stub
}
@Override
public void onSourceLoadCompleted(UserProject projectInfo) {
// TODO Auto-generated method stub
}
}
......@@ -12,6 +12,10 @@ import com.google.appinventor.shared.rpc.project.GalleryAppListResult;
import com.google.appinventor.shared.rpc.project.GalleryComment;
import com.google.appinventor.shared.rpc.project.UserProject;
/**
* UI objects will call gallery client to get apps, the methods here are the callback
*
*/
public interface GalleryRequestListener {
public static final int REQUEST_FEATURED=1;
......@@ -22,10 +26,28 @@ public interface GalleryRequestListener {
public static final int REQUEST_MOSTVIEWED=6;
/**
* UI objects will call gallery client to get apps, the methods here are the callback
* After a request for an application list is proceed this method will be called.
*
* @param appsResult
* @param requestID
* @param refreshable
* @return true if the listener should be removed, otherwise false.
*/
public void onAppListRequestCompleted(GalleryAppListResult appsResult, int requestID, boolean refreshable);
public void onCommentsRequestCompleted(List<GalleryComment> comments);
public void onSourceLoadCompleted(UserProject projectInfo);
public boolean onAppListRequestCompleted(GalleryAppListResult appsResult, int requestID, boolean refreshable);
/**
* After a request for application comments has been completed, this method will be called.
*
* @param comments
* @return true if the listener should be removed, otherwise false.
*/
public boolean onCommentsRequestCompleted(List<GalleryComment> comments);
/**
* After a request for sources has been completed, this method will be called.
*
* @param projectInfo
* @return true if the listener should be removed, otherwise false.
*/
public boolean onSourceLoadCompleted(UserProject projectInfo);
}
\ No newline at end of file
......@@ -74,6 +74,12 @@ public interface Images extends Resources {
@Source("com/google/appinventor/images/navigationbar.png")
ImageResource navigationbar();
/**
* Spinning/wait graphic to indicate long-running operations.
*/
@Source("com/google/appinventor/images/spin_16.gif")
ImageResource waitingIcon();
/**
* Designer palette item: question mark for more component information
*/
......
......@@ -65,10 +65,12 @@ import com.google.appinventor.shared.rpc.help.HelpService;
import com.google.appinventor.shared.rpc.help.HelpServiceAsync;
import com.google.appinventor.shared.rpc.project.FileNode;
import com.google.appinventor.shared.rpc.project.GalleryAppListResult;
import com.google.appinventor.shared.rpc.project.GalleryComment;
import com.google.appinventor.shared.rpc.project.GallerySettings;
import com.google.appinventor.shared.rpc.project.ProjectRootNode;
import com.google.appinventor.shared.rpc.project.ProjectService;
import com.google.appinventor.shared.rpc.project.ProjectServiceAsync;
import com.google.appinventor.shared.rpc.project.UserProject;
import com.google.appinventor.shared.rpc.project.GalleryService;
import com.google.appinventor.shared.rpc.project.GalleryServiceAsync;
import com.google.appinventor.shared.rpc.project.youngandroid.YoungAndroidSourceNode;
......@@ -261,6 +263,8 @@ public class Ode implements EntryPoint {
private boolean screensLocked;
private boolean galleryInitialized = false;
private SplashConfig splashConfig; // Splash Screen Configuration
/**
......@@ -343,14 +347,11 @@ public class Ode implements EntryPoint {
ProjectListBox.getProjectListBox().getProjectList().setPublishedHeaderVisible(true);
projectToolbar.setPublishOrUpdateButtonVisible(true);
GalleryClient.getInstance().setSystemEnvironment(settings.getEnvironment());
GalleryListBox.loadGalleryList();
topPanel.showGalleryLink(true);
if(user.isModerator()){
ModerationPageBox.loadModerationPage();
topPanel.showModerationLink(true);
}
topPanel.updateAccountMessageButton();
PrivateUserProfileTabPanel.getPrivateUserProfileTabPanel().loadProfileImage();
}else{
topPanel.showModerationLink(false);
topPanel.showGalleryLink(false);
......@@ -430,6 +431,10 @@ public class Ode implements EntryPoint {
* Switch to the Gallery tab
*/
public void switchToGalleryView() {
if (!galleryInitialized) {
// Gallery initialization is deferred until now.
initializeGallery();
}
currentView = GALLERY;
deckPanel.showWidget(galleryTabIndex);
}
......@@ -438,6 +443,10 @@ public class Ode implements EntryPoint {
* Switch to the Gallery App
*/
public void switchToGalleryAppView(GalleryApp app, int editStatus) {
if (!galleryInitialized) {
// Gallery initialization is deferred until now.
initializeGallery();
}
currentView = GALLERYAPP;
GalleryAppBox.setApp(app, editStatus);
deckPanel.showWidget(galleryAppTabIndex);
......@@ -482,6 +491,9 @@ public class Ode implements EntryPoint {
* Switch to the Moderation Page tab
*/
public void switchToModerationPageView() {
if (!galleryInitialized) {
initializeGallery();
}
currentView = MODERATIONPAGE;
deckPanel.showWidget(moderationPageTabIndex);
}
......@@ -950,29 +962,12 @@ public class Ode implements EntryPoint {
// Gallery list tab
VerticalPanel gVertPanel = new VerticalPanel();
gVertPanel.setWidth("100%");
gVertPanel.setSpacing(0);
galleryListToolbar = new GalleryToolbar();
gVertPanel.add(galleryListToolbar);
HorizontalPanel appListPanel = new HorizontalPanel();
appListPanel.setWidth("100%");
appListPanel.add(GalleryListBox.getGalleryListBox());
gVertPanel.add(appListPanel);
gVertPanel.add(createLoadingWidget());
galleryTabIndex = deckPanel.getWidgetCount();
deckPanel.add(gVertPanel);
// Gallery app tab
VerticalPanel aVertPanel = new VerticalPanel();
aVertPanel.setWidth("100%");
aVertPanel.setSpacing(0);
galleryPageToolbar = new GalleryToolbar();
aVertPanel.add(galleryPageToolbar);
HorizontalPanel appPanel = new HorizontalPanel();
appPanel.setWidth("100%");
appPanel.add(GalleryAppBox.getGalleryAppBox());
aVertPanel.add(appPanel);
galleryAppTabIndex = deckPanel.getWidgetCount();
deckPanel.add(aVertPanel);
......@@ -1014,14 +1009,6 @@ public class Ode implements EntryPoint {
// Moderation Page tab
VerticalPanel mPVertPanel = new VerticalPanel();
mPVertPanel.setWidth("100%");
mPVertPanel.setSpacing(0);
HorizontalPanel moderationPagePanel = new HorizontalPanel();
moderationPagePanel.setWidth("100%");
moderationPagePanel.add(ModerationPageBox.getModerationPageBox());
mPVertPanel.add(moderationPagePanel);
moderationPageTabIndex = deckPanel.getWidgetCount();
deckPanel.add(mPVertPanel);
......@@ -2214,6 +2201,83 @@ public class Ode implements EntryPoint {
});
}
private void initializeGallery() {
VerticalPanel gVertPanel = (VerticalPanel)deckPanel.getWidget(galleryTabIndex);
gVertPanel.setWidth("100%");
gVertPanel.setSpacing(0);
galleryListToolbar = new GalleryToolbar();
gVertPanel.add(galleryListToolbar);
HorizontalPanel appListPanel = new HorizontalPanel();
appListPanel.setWidth("100%");
appListPanel.add(GalleryListBox.getGalleryListBox());
gVertPanel.add(appListPanel);
VerticalPanel aVertPanel = (VerticalPanel)deckPanel.getWidget(galleryAppTabIndex);
aVertPanel.setWidth("100%");
aVertPanel.setSpacing(0);
galleryPageToolbar = new GalleryToolbar();
aVertPanel.add(galleryPageToolbar);
HorizontalPanel appPanel = new HorizontalPanel();
appPanel.setWidth("100%");
appPanel.add(GalleryAppBox.getGalleryAppBox());
aVertPanel.add(appPanel);
VerticalPanel mPVertPanel = (VerticalPanel)deckPanel.getWidget(moderationPageTabIndex);
mPVertPanel.setWidth("100%");
mPVertPanel.setSpacing(0);
HorizontalPanel moderationPagePanel = new HorizontalPanel();
moderationPagePanel.setWidth("100%");
moderationPagePanel.add(ModerationPageBox.getModerationPageBox());
mPVertPanel.add(moderationPagePanel);
GalleryListBox.loadGalleryList();
if (user.isModerator()) {
ModerationPageBox.loadModerationPage();
}
PrivateUserProfileTabPanel.getPrivateUserProfileTabPanel().loadProfileImage();
galleryInitialized = true;
}
private Widget createLoadingWidget() {
final HorizontalPanel container = new HorizontalPanel();
container.setWidth("100%");
container.setSpacing(0);
container.setHorizontalAlignment(HorizontalPanel.ALIGN_CENTER);
HorizontalPanel panel = new HorizontalPanel();
Image image = new Image();
image.setResource(IMAGES.waitingIcon());
panel.add(image);
Label label = new Label();
label.setText(MESSAGES.defaultRpcMessage());
panel.add(label);
container.add(panel);
GalleryClient.getInstance().addListener(new GalleryRequestListener() {
private void hideLoadingWidget() {
if (container.getParent() != null) {
container.clear();
container.removeFromParent();
}
}
@Override
public boolean onAppListRequestCompleted(GalleryAppListResult appsResult, int requestID, boolean refreshable) {
hideLoadingWidget();
return true;
}
@Override
public boolean onCommentsRequestCompleted(List<GalleryComment> comments) {
hideLoadingWidget();
return true;
}
@Override
public boolean onSourceLoadCompleted(UserProject projectInfo) {
hideLoadingWidget();
return true;
}
});
return container;
}
// Native code to set the top level rendezvousServer variable
// where blockly code can easily find it.
private native void setRendezvousServer(String server) /*-{
......
......@@ -6,9 +6,13 @@
package com.google.appinventor.client.boxes;
import com.google.appinventor.client.Ode;
import com.google.appinventor.client.explorer.youngandroid.GalleryPage;
import com.google.appinventor.shared.rpc.project.GalleryApp;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
......@@ -50,6 +54,18 @@ public final class GalleryAppBox extends FlowPanel {
*/
private GalleryAppBox() {
gContainer = new FlowPanel();
final HorizontalPanel container = new HorizontalPanel();
container.setWidth("100%");
container.setSpacing(0);
container.setHorizontalAlignment(HorizontalPanel.ALIGN_CENTER);
HorizontalPanel panel = new HorizontalPanel();
Image image = new Image();
image.setResource(Ode.getImageBundle().waitingIcon());
panel.add(image);
Label label = new Label();
label.setText(Ode.getMessages().defaultRpcMessage());
panel.add(label);
gContainer.add(panel);
this.add(gContainer);
}
}
......@@ -502,28 +502,29 @@ public class GalleryList extends Composite implements GalleryRequestListener {
* @param refreshable whether or not clear container
* @see GalleryRequestListener
*/
public void onAppListRequestCompleted(GalleryAppListResult appsResult, int requestId, boolean refreshable)
public boolean onAppListRequestCompleted(GalleryAppListResult appsResult, int requestId, boolean refreshable)
{
List<GalleryApp> apps = appsResult.getApps();
if (apps != null)
refreshApps(appsResult, requestId, refreshable);
else
OdeLog.log("apps was null");
return false;
}
/**
* Process the results after retrieving list of GalleryComment
* @see GalleryRequestListener
*/
public void onCommentsRequestCompleted(List<GalleryComment> comments){
public boolean onCommentsRequestCompleted(List<GalleryComment> comments){
return false;
}
/**
* Process the results after retrieving list of UserProject
* @see GalleryRequestListener
*/
public void onSourceLoadCompleted(UserProject projectInfo) {
public boolean onSourceLoadCompleted(UserProject projectInfo) {
return false;
}
}
......
......@@ -1446,11 +1446,12 @@ panel
* gallery page to listen to
*/
@Override
public void onAppListRequestCompleted(GalleryAppListResult appResults, int requestId, boolean refreshable) {
public boolean onAppListRequestCompleted(GalleryAppListResult appResults, int requestId, boolean refreshable) {
if (appResults != null && appResults.getApps() != null)
refreshApps(appResults, requestId, refreshable);
else
OdeLog.log("apps was null");
return false;
}
/**
......@@ -1458,15 +1459,16 @@ panel
* gallery page to listen to
*/
@Override
public void onCommentsRequestCompleted(List<GalleryComment> comments) {
public boolean onCommentsRequestCompleted(List<GalleryComment> comments) {
galleryGF.generateAppPageComments(comments, appCommentsList);
if (comments == null)
OdeLog.log("comment list was null");
return false;
}
@Override
public void onSourceLoadCompleted(UserProject projectInfo) {
public boolean onSourceLoadCompleted(UserProject projectInfo) {
return false;
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment