Implement change list for reviewing changes
This is a first step to provide a change list from which the user can
select changes for review. This change only implements a basic version
of the change list that is not fully implemented yet:
- Selecting a change does not trigger any action yet.
- It only shows the first page of changes, it is not possible yet to
load further pages.
- The entry for a change does not yet display all information that we
would like to show here (e.g. current votes are missing).
Change-Id: I36bf7b3737240b8434475590c13c47e0afa01a3a
Signed-off-by: Edwin Kempin <ekempin@google.com>
diff --git a/app/src/main/java/com/google/reviewit/AbandonFragment.java b/app/src/main/java/com/google/reviewit/AbandonFragment.java
index 4233411..dcc2137 100644
--- a/app/src/main/java/com/google/reviewit/AbandonFragment.java
+++ b/app/src/main/java/com/google/reviewit/AbandonFragment.java
@@ -50,7 +50,7 @@
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- Change change = getApp().getActionHandler().getCurrentChange();
+ Change change = getApp().getSortActionHandler().getCurrentChange();
setTitle(getString(R.string.abandon_change_title, change.info._number));
init(change);
}
diff --git a/app/src/main/java/com/google/reviewit/AddReviewerFragment.java b/app/src/main/java/com/google/reviewit/AddReviewerFragment.java
index c53071c..7e25d7f 100644
--- a/app/src/main/java/com/google/reviewit/AddReviewerFragment.java
+++ b/app/src/main/java/com/google/reviewit/AddReviewerFragment.java
@@ -77,7 +77,7 @@
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- Change change = getApp().getActionHandler().getCurrentChange();
+ Change change = getApp().getSortActionHandler().getCurrentChange();
initInputField(change);
try {
displayReviewers(change);
diff --git a/app/src/main/java/com/google/reviewit/BaseFragment.java b/app/src/main/java/com/google/reviewit/BaseFragment.java
index 9babd93..e64d33a 100644
--- a/app/src/main/java/com/google/reviewit/BaseFragment.java
+++ b/app/src/main/java/com/google/reviewit/BaseFragment.java
@@ -31,7 +31,7 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
-import com.google.reviewit.app.ActionHandler;
+import com.google.reviewit.app.SortActionHandler;
import com.google.reviewit.app.ReviewItApp;
import com.google.reviewit.util.TaskObserver;
import com.google.reviewit.util.WidgetUtil;
@@ -121,8 +121,8 @@
return ((ReviewItApp) getActivity().getApplication());
}
- protected ActionHandler getActionHandler() {
- return getApp().getActionHandler();
+ protected SortActionHandler getSortActionHandler() {
+ return getApp().getSortActionHandler();
}
public void display(
diff --git a/app/src/main/java/com/google/reviewit/DetailedChangeFragment.java b/app/src/main/java/com/google/reviewit/DetailedChangeFragment.java
index f99d812..2991696 100644
--- a/app/src/main/java/com/google/reviewit/DetailedChangeFragment.java
+++ b/app/src/main/java/com/google/reviewit/DetailedChangeFragment.java
@@ -31,7 +31,7 @@
import com.google.gerrit.extensions.client.ChangeStatus;
import com.google.gerrit.extensions.common.FileInfo;
-import com.google.reviewit.app.ActionHandler;
+import com.google.reviewit.app.SortActionHandler;
import com.google.reviewit.app.Change;
import com.google.reviewit.util.ChangeUtil;
import com.google.reviewit.widget.ChangeBox;
@@ -85,7 +85,7 @@
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- Change change = getApp().getActionHandler().getCurrentChange();
+ Change change = getApp().getSortActionHandler().getCurrentChange();
setTitle(getString(R.string.detailed_change_title, change.info._number));
setHasOptionsMenu(true);
init();
@@ -217,7 +217,7 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- ActionHandler actionHandler = getApp().getActionHandler();
+ SortActionHandler actionHandler = getApp().getSortActionHandler();
inflater.inflate(R.menu.menu_detailed_change, menu);
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
@@ -237,7 +237,7 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- ActionHandler actionHandler = getApp().getActionHandler();
+ SortActionHandler actionHandler = getApp().getSortActionHandler();
switch (item.getItemId()) {
case R.id.action_add_reviewer:
display(AddReviewerFragment.create(getClass()));
diff --git a/app/src/main/java/com/google/reviewit/PostReviewFragment.java b/app/src/main/java/com/google/reviewit/PostReviewFragment.java
index b887e48..bb431db 100644
--- a/app/src/main/java/com/google/reviewit/PostReviewFragment.java
+++ b/app/src/main/java/com/google/reviewit/PostReviewFragment.java
@@ -71,7 +71,7 @@
int vote = getArguments().getInt(VOTE);
update(vote);
- Change change = getApp().getActionHandler().getCurrentChange();
+ Change change = getApp().getSortActionHandler().getCurrentChange();
setTitle(getString(R.string.detailed_change_title, change.info._number));
init(change);
diff --git a/app/src/main/java/com/google/reviewit/SortSettingFragment.java b/app/src/main/java/com/google/reviewit/QuerySettingsFragment.java
similarity index 97%
rename from app/src/main/java/com/google/reviewit/SortSettingFragment.java
rename to app/src/main/java/com/google/reviewit/QuerySettingsFragment.java
index 5efb057..5ab3f1a 100644
--- a/app/src/main/java/com/google/reviewit/SortSettingFragment.java
+++ b/app/src/main/java/com/google/reviewit/QuerySettingsFragment.java
@@ -25,12 +25,12 @@
import com.google.reviewit.app.ServerConfig;
import com.google.reviewit.util.WidgetUtil;
-public class SortSettingFragment extends BaseFragment {
+public class QuerySettingsFragment extends BaseFragment {
private static final String LABEL_REGEXP = "^[a-zA-Z][a-zA-Z0-9]*$";
@Override
protected @LayoutRes int getLayout() {
- return R.layout.content_sort_settings;
+ return R.layout.content_query_settings;
}
@Override
diff --git a/app/src/main/java/com/google/reviewit/RestoreFragment.java b/app/src/main/java/com/google/reviewit/RestoreFragment.java
index 5ec9622..45d398a 100644
--- a/app/src/main/java/com/google/reviewit/RestoreFragment.java
+++ b/app/src/main/java/com/google/reviewit/RestoreFragment.java
@@ -50,7 +50,7 @@
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- Change change = getApp().getActionHandler().getCurrentChange();
+ Change change = getApp().getSortActionHandler().getCurrentChange();
setTitle(getString(R.string.restore_change_title, change.info._number));
init(change);
}
diff --git a/app/src/main/java/com/google/reviewit/ReviewChangesFragment.java b/app/src/main/java/com/google/reviewit/ReviewChangesFragment.java
index b38f651..5c68c1e 100644
--- a/app/src/main/java/com/google/reviewit/ReviewChangesFragment.java
+++ b/app/src/main/java/com/google/reviewit/ReviewChangesFragment.java
@@ -14,12 +14,184 @@
package com.google.reviewit;
+import android.os.Bundle;
import android.support.annotation.LayoutRes;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.reviewit.app.Change;
+import com.google.reviewit.app.QueryHandler;
+import com.google.reviewit.util.ObservableAsynTask;
+import com.google.reviewit.util.TaskObserver;
+import com.google.reviewit.widget.ChangeEntry;
+
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.reviewit.util.LayoutUtil.matchAndFixedLayout;
+import static com.google.reviewit.util.WidgetUtil.setGone;
+import static com.google.reviewit.util.WidgetUtil.setInvisible;
+import static com.google.reviewit.util.WidgetUtil.setVisible;
public class ReviewChangesFragment extends BaseFragment {
+ private static final String TAG = ReviewChangesFragment.class.getName();
@Override
protected @LayoutRes int getLayout() {
return R.layout.content_review_changes;
}
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ setHasOptionsMenu(true);
+
+ TaskObserver.enableProgressBar(getWindow());
+ init();
+ display();
+ }
+
+ private void init() {
+ v(R.id.reloadButton).setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ reloadQuery();
+ }
+ });
+
+ // TODO detect when scrolled to the end and automatically load next page
+ }
+
+ private void display() {
+ if (!isOnline()) {
+ setInvisible(v(R.id.progress));
+ setGone(v(R.id.initialProgress));
+ setVisible(v(R.id.statusText, R.id.reloadButton));
+ TextView statusText = tv(R.id.statusText);
+ statusText.setText(getString(R.string.no_network));
+ statusText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15);
+ return;
+ }
+
+ new ObservableAsynTask<Void, Void, ChangeListData>() {
+ private View progress;
+ private View initialProgress;
+ private View reloadButton;
+ private TextView statusText;
+ private ViewGroup changeList;
+
+ @Override
+ protected void preExecute() {
+ super.preExecute();
+ progress = v(R.id.progress);
+ initialProgress = v(R.id.initialProgress);
+ reloadButton = v(R.id.reloadButton);
+ statusText = tv(R.id.statusText);
+ changeList = vg(R.id.changeList);
+ }
+
+ @Override
+ protected ChangeListData doInBackground(Void... v) {
+ try {
+ QueryHandler queryHandler = getApp().getQueryHandler();
+ if (queryHandler.hasNext()) {
+ return new ChangeListData(queryHandler.next());
+ } else {
+ return new ChangeListData(Collections.<Change>emptyList());
+ }
+ } catch (RestApiException e) {
+ // e.g. server not reachable
+ Log.e(TAG, "Request failed", e);
+ if (e.getCause() != null) {
+ return new ChangeListData(getString(R.string.error_with_cause,
+ e.getMessage(), e.getCause().getMessage()));
+ } else {
+ return new ChangeListData(e.getMessage());
+ }
+ }
+ }
+
+ protected void postExecute(ChangeListData changeListData) {
+ super.postExecute(changeListData);
+
+ if (getActivity() == null) {
+ // user navigated away while we were waiting for the request
+ return;
+ }
+
+ getActivity().invalidateOptionsMenu();
+ setInvisible(progress);
+ setGone(initialProgress, reloadButton);
+
+ if (changeListData.error != null) {
+ statusText.setText(changeListData.error);
+ return;
+ }
+
+ if (!changeListData.changeList.isEmpty()) {
+ setGone(statusText);
+ for (Change change : changeListData.changeList) {
+ ChangeEntry changeEntry = new ChangeEntry(getContext());
+ changeEntry.init(getApp(), change);
+ changeList.addView(changeEntry);
+ addSeparator(changeList);
+ }
+ } else {
+ statusText.setText(getString(R.string.no_changes_match));
+ }
+ }
+ }.execute();
+ }
+
+ private void addSeparator(ViewGroup viewGroup) {
+ View separator = new View(getContext());
+ separator.setLayoutParams(
+ matchAndFixedLayout(widgetUtil.dpToPx(1)));
+ separator.setBackgroundColor(widgetUtil.color(R.color.separator));
+ viewGroup.addView(separator);
+ }
+
+ private void reloadQuery() {
+ getApp().getQueryHandler().reset();
+ display(getClass(), false);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.menu_review_changes, menu);
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_reload_query:
+ reloadQuery();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private static class ChangeListData {
+ final List<Change> changeList;
+ final String error;
+
+ ChangeListData(List<Change> changeList) {
+ this.changeList = changeList;
+ this.error = null;
+ }
+
+ ChangeListData(String error) {
+ this.changeList = null;
+ this.error = error;
+ }
+ }
}
diff --git a/app/src/main/java/com/google/reviewit/SettingsFragment.java b/app/src/main/java/com/google/reviewit/SettingsFragment.java
index c81210e..67f0c0f 100644
--- a/app/src/main/java/com/google/reviewit/SettingsFragment.java
+++ b/app/src/main/java/com/google/reviewit/SettingsFragment.java
@@ -41,10 +41,10 @@
}
});
- v(R.id.sortConfig).setOnClickListener(new View.OnClickListener() {
+ v(R.id.queryConfig).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- display(SortSettingFragment.class);
+ display(QuerySettingsFragment.class);
}
});
}
diff --git a/app/src/main/java/com/google/reviewit/SortChangesFragment.java b/app/src/main/java/com/google/reviewit/SortChangesFragment.java
index df116a0..2969891 100644
--- a/app/src/main/java/com/google/reviewit/SortChangesFragment.java
+++ b/app/src/main/java/com/google/reviewit/SortChangesFragment.java
@@ -37,7 +37,7 @@
import com.google.gerrit.extensions.client.ChangeStatus;
import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.reviewit.app.ActionHandler;
+import com.google.reviewit.app.SortActionHandler;
import com.google.reviewit.app.Change;
import com.google.reviewit.app.ConfigManager;
import com.google.reviewit.app.QueryConfig;
@@ -74,8 +74,8 @@
setHasOptionsMenu(true);
- if (getActionHandler().hasCurrentChange()) {
- getActionHandler().pushBack();
+ if (getSortActionHandler().hasCurrentChange()) {
+ getSortActionHandler().pushBack();
}
TaskObserver.enableProgressBar(getWindow());
@@ -92,7 +92,7 @@
ConfigManager cfgManager = getApp().getConfigManager();
QueryConfig config = cfgManager.getQueryConfig();
if (!config.isComplete()) {
- display(SortSettingFragment.class);
+ display(QuerySettingsFragment.class);
return;
}
@@ -105,7 +105,7 @@
return;
}
- if (getActionHandler().isQueryNeeded()) {
+ if (getSortActionHandler().isQueryNeeded()) {
if (v(R.id.changeBox) == null) {
setVisible(v(R.id.loadingBox));
setInvisible(v(R.id.progress));
@@ -115,7 +115,7 @@
setVisible(v(R.id.progress));
}
} else {
- Change change = getActionHandler().preview();
+ Change change = getSortActionHandler().preview();
if (change != null) {
ChangeUtil.colorBackground(root, change);
}
@@ -144,7 +144,7 @@
@Override
protected ChangeData doInBackground(Void... v) {
try {
- ActionHandler actionHandler = getActionHandler();
+ SortActionHandler actionHandler = getSortActionHandler();
if (actionHandler.hasNext()) {
Change change = actionHandler.next();
int queueSize = actionHandler.getQueueSize();
@@ -235,16 +235,16 @@
v(R.id.skipButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
disableButtons();
- getActionHandler().skip();
- animate(changeBox, ActionHandler.Action.SKIP);
+ getSortActionHandler().skip();
+ animate(changeBox, SortActionHandler.Action.SKIP);
}
});
View.OnClickListener onStarClickListener = new View.OnClickListener() {
public void onClick(View v) {
disableButtons();
- getActionHandler().star();
- animate(changeBox, ActionHandler.Action.STAR);
+ getSortActionHandler().star();
+ animate(changeBox, SortActionHandler.Action.STAR);
}
};
v(R.id.starButton).setOnClickListener(onStarClickListener);
@@ -253,8 +253,8 @@
View.OnClickListener onIgnoreClickListener = new View.OnClickListener() {
public void onClick(View v) {
disableButtons();
- getActionHandler().ignore();
- animate(changeBox, ActionHandler.Action.IGNORE);
+ getSortActionHandler().ignore();
+ animate(changeBox, SortActionHandler.Action.IGNORE);
}
};
v(R.id.ignoreButton).setOnClickListener(onIgnoreClickListener);
@@ -304,7 +304,7 @@
final ViewGroup resultBox = vg(R.id.resultBox);
changeBox.findViewById(R.id.changeBoxUpperPart).setOnTouchListener(
new View.OnTouchListener() {
- private ActionHandler.Action action = ActionHandler.Action.NONE;
+ private SortActionHandler.Action action = SortActionHandler.Action.NONE;
private int x;
private int y;
@@ -330,9 +330,9 @@
if (eventX > (screenCenter + (screenCenter / 2))) {
((GradientDrawable) changeBox.getBackground())
.setColor(widgetUtil.color(R.color.commitMessageStar));
- action = ActionHandler.Action.STAR;
+ action = SortActionHandler.Action.STAR;
} else {
- action = ActionHandler.Action.NONE;
+ action = SortActionHandler.Action.NONE;
((GradientDrawable) changeBox.getBackground())
.setColor(widgetUtil.color(R.color.commitMessage));
}
@@ -342,9 +342,9 @@
if (eventX < (screenCenter / 2)) {
((GradientDrawable) changeBox.getBackground())
.setColor(widgetUtil.color(R.color.commitMessageIgnore));
- action = ActionHandler.Action.IGNORE;
+ action = SortActionHandler.Action.IGNORE;
} else {
- action = ActionHandler.Action.NONE;
+ action = SortActionHandler.Action.NONE;
((GradientDrawable) changeBox.getBackground())
.setColor(widgetUtil.color(R.color.commitMessage));
}
@@ -355,17 +355,17 @@
.setColor(widgetUtil.color(R.color.commitMessage));
switch (action) {
case STAR:
- getActionHandler().star();
+ getSortActionHandler().star();
resultBox.removeView(changeBox);
display();
break;
case IGNORE:
- getActionHandler().ignore();
+ getSortActionHandler().ignore();
resultBox.removeView(changeBox);
display();
break;
case SKIP:
- getActionHandler().skip();
+ getSortActionHandler().skip();
resultBox.removeView(changeBox);
display();
break;
@@ -388,7 +388,7 @@
}
private void animate(
- final View changeBox, final ActionHandler.Action action) {
+ final View changeBox, final SortActionHandler.Action action) {
final ViewGroup resultBox = vg(R.id.resultBox);
Point screenSize = getScreenSize();
final int screenCenter = screenSize.x / 2;
@@ -517,7 +517,7 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- ActionHandler actionHandler = getActionHandler();
+ SortActionHandler actionHandler = getSortActionHandler();
inflater.inflate(R.menu.menu_sort_changes, menu);
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
@@ -574,7 +574,7 @@
}
private void undo() {
- ActionHandler actionHandler = getActionHandler();
+ SortActionHandler actionHandler = getSortActionHandler();
if (!actionHandler.undoPossible()) {
return;
}
@@ -615,17 +615,17 @@
display(SortChangesFragment.class);
}
}
- }.execute(getActionHandler().getCurrentChange());
+ }.execute(getSortActionHandler().getCurrentChange());
}
private void reloadQuery() {
- getActionHandler().reset();
+ getSortActionHandler().reset();
display(getClass(), false);
}
@Override
public boolean onBackPressed() {
- if (getActionHandler().undoPossible()) {
+ if (getSortActionHandler().undoPossible()) {
undo();
return true;
}
diff --git a/app/src/main/java/com/google/reviewit/UnifiedDiffFragment.java b/app/src/main/java/com/google/reviewit/UnifiedDiffFragment.java
index 4db29a2..4a31052 100644
--- a/app/src/main/java/com/google/reviewit/UnifiedDiffFragment.java
+++ b/app/src/main/java/com/google/reviewit/UnifiedDiffFragment.java
@@ -84,7 +84,7 @@
? getArguments().getString(PATH)
: null;
- Change change = getApp().getActionHandler().getCurrentChange();
+ Change change = getApp().getSortActionHandler().getCurrentChange();
checkState(change != null, "Change not set");
Map<String, FileInfo> files = change.currentRevision().files;
root = (ScrollWithHeadingsView) v(R.id.unifiedDiffRoot);
diff --git a/app/src/main/java/com/google/reviewit/app/QueryConfig.java b/app/src/main/java/com/google/reviewit/app/QueryConfig.java
index ea87e08..4759c9d 100644
--- a/app/src/main/java/com/google/reviewit/app/QueryConfig.java
+++ b/app/src/main/java/com/google/reviewit/app/QueryConfig.java
@@ -16,6 +16,9 @@
import com.google.common.base.Strings;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
public class QueryConfig {
public final String serverId;
public final String query;
@@ -27,6 +30,15 @@
this.label = label;
}
+ public String encodedQuery() {
+ try {
+ // TODO use StandardCharsets.UTF_8.name() with API level 19
+ return URLEncoder.encode(query, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
public boolean isComplete() {
return !Strings.isNullOrEmpty(serverId)
&& !Strings.isNullOrEmpty(query)
diff --git a/app/src/main/java/com/google/reviewit/app/QueryHandler.java b/app/src/main/java/com/google/reviewit/app/QueryHandler.java
new file mode 100644
index 0000000..bdaa6f3
--- /dev/null
+++ b/app/src/main/java/com/google/reviewit/app/QueryHandler.java
@@ -0,0 +1,110 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.reviewit.app;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.gerrit.extensions.client.ListChangesOption;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class QueryHandler {
+ /**
+ * Number of changes that should be fetched at once from the server.
+ */
+ private static final int LIMIT_QUERY = 25;
+
+ private final Gerrit gerrit;
+
+ private final LinkedList<Change> result = new LinkedList<>();
+
+ private QueryConfig config;
+
+ /**
+ * Number of changes which should be skipped when querying the next changes
+ * from the server.
+ */
+ private int start = 0;
+
+ private int page = 0;
+
+ /**
+ * Whether there are more changes at the server.
+ */
+ private boolean more = true;
+
+ QueryHandler(ConfigManager cfgManager, Gerrit gerrit) {
+ this.gerrit = gerrit;
+ this.config = cfgManager.getQueryConfig();
+
+ cfgManager.addUpdateListener(new ConfigManager.OnUpdate() {
+ @Override
+ public void onUpdate(QueryConfig cfg) {
+ config = cfg;
+ reset();
+ }
+ });
+ }
+
+ public List<Change> next() throws RestApiException {
+ query();
+ return result.subList(page * LIMIT_QUERY, (page + 1) * LIMIT_QUERY);
+ }
+
+ public boolean hasNext() {
+ return more;
+ }
+
+ private void query() throws RestApiException {
+ result.addAll(Collections2.transform(Collections2.filter(
+ gerrit.api()
+ .changes()
+ .query(config.encodedQuery())
+ .withOption(ListChangesOption.ALL_FILES)
+ .withOption(ListChangesOption.CURRENT_COMMIT)
+ .withOption(ListChangesOption.CURRENT_REVISION)
+ .withOption(ListChangesOption.DETAILED_ACCOUNTS)
+ .withOption(ListChangesOption.DETAILED_LABELS)
+ .withLimit(LIMIT_QUERY)
+ .withStart(start)
+ .get(), new Predicate<ChangeInfo>() {
+ @Override
+ public boolean apply(ChangeInfo changeInfo) {
+ // filter out changes with no revisions
+ return changeInfo.revisions != null;
+ }
+ }), new Function<ChangeInfo, Change>() {
+ @Override
+ public Change apply(ChangeInfo changeInfo) {
+ return new Change(gerrit.api(), changeInfo);
+ }
+ }));
+ start += LIMIT_QUERY;
+ more = !result.isEmpty() && (result.getLast().info._moreChanges != null
+ ? result.getLast().info._moreChanges
+ : false);
+ }
+
+ public void reset() {
+ result.clear();
+ start = 0;
+ more = true;
+ page = 0;
+ }
+}
diff --git a/app/src/main/java/com/google/reviewit/app/ReviewItApp.java b/app/src/main/java/com/google/reviewit/app/ReviewItApp.java
index 10fb519..b2efb88 100644
--- a/app/src/main/java/com/google/reviewit/app/ReviewItApp.java
+++ b/app/src/main/java/com/google/reviewit/app/ReviewItApp.java
@@ -32,7 +32,8 @@
public class ReviewItApp extends Application {
private static final String TAG = ReviewItApp.class.getName();
- private ActionHandler actionHandler;
+ private QueryHandler queryHandler;
+ private SortActionHandler sortActionHandler;
private AvatarCache avatarCache;
private ConfigManager cfgManager;
private ExecutorService executor;
@@ -94,11 +95,18 @@
super.onCreate();
}
- public ActionHandler getActionHandler() {
- if (actionHandler == null) {
- actionHandler = new ActionHandler(getConfigManager(), getGerrit());
+ public QueryHandler getQueryHandler() {
+ if (queryHandler == null) {
+ queryHandler = new QueryHandler(getConfigManager(), getGerrit());
}
- return actionHandler;
+ return queryHandler;
+ }
+
+ public SortActionHandler getSortActionHandler() {
+ if (sortActionHandler == null) {
+ sortActionHandler = new SortActionHandler(getConfigManager(), getGerrit());
+ }
+ return sortActionHandler;
}
public AvatarCache getAvatarCache() {
diff --git a/app/src/main/java/com/google/reviewit/app/ActionHandler.java b/app/src/main/java/com/google/reviewit/app/SortActionHandler.java
similarity index 96%
rename from app/src/main/java/com/google/reviewit/app/ActionHandler.java
rename to app/src/main/java/com/google/reviewit/app/SortActionHandler.java
index c182ea9..2a95b1e 100644
--- a/app/src/main/java/com/google/reviewit/app/ActionHandler.java
+++ b/app/src/main/java/com/google/reviewit/app/SortActionHandler.java
@@ -23,7 +23,7 @@
import java.util.LinkedList;
-public class ActionHandler {
+public class SortActionHandler {
public enum Action {
/**
* Do nothing.
@@ -90,7 +90,7 @@
*/
private boolean more = true;
- ActionHandler(ConfigManager cfgManager, Gerrit gerrit) {
+ SortActionHandler(ConfigManager cfgManager, Gerrit gerrit) {
this.gerrit = gerrit;
this.config = cfgManager.getQueryConfig();
@@ -147,7 +147,7 @@
toProcess.addAll(Collections2.transform(Collections2.filter(
gerrit.api()
.changes()
- .query(encodeQuery(config.query))
+ .query(config.encodedQuery())
.withOption(ListChangesOption.ALL_FILES)
.withOption(ListChangesOption.CURRENT_COMMIT)
.withOption(ListChangesOption.CURRENT_REVISION)
@@ -179,10 +179,6 @@
return toProcess.size() < THRESHOLD_QUEUE && more;
}
- private static String encodeQuery(String query) {
- return query.replaceAll(" ", "+");
- }
-
/**
* Stars the current change.
*/
diff --git a/app/src/main/java/com/google/reviewit/util/LayoutUtil.java b/app/src/main/java/com/google/reviewit/util/LayoutUtil.java
index 907ea6c..ff19c94 100644
--- a/app/src/main/java/com/google/reviewit/util/LayoutUtil.java
+++ b/app/src/main/java/com/google/reviewit/util/LayoutUtil.java
@@ -34,6 +34,11 @@
ViewGroup.LayoutParams.WRAP_CONTENT);
}
+ public static ViewGroup.LayoutParams matchAndFixedLayout(int height) {
+ return new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, height);
+ }
+
public static TableLayout.LayoutParams matchAndWrapTableLayout() {
return new TableLayout.LayoutParams(
TableLayout.LayoutParams.MATCH_PARENT,
diff --git a/app/src/main/java/com/google/reviewit/widget/ChangeEntry.java b/app/src/main/java/com/google/reviewit/widget/ChangeEntry.java
new file mode 100644
index 0000000..cfd5e37
--- /dev/null
+++ b/app/src/main/java/com/google/reviewit/widget/ChangeEntry.java
@@ -0,0 +1,50 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.reviewit.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.reviewit.R;
+import com.google.reviewit.app.Change;
+import com.google.reviewit.app.ReviewItApp;
+import com.google.reviewit.util.WidgetUtil;
+
+public class ChangeEntry extends LinearLayout {
+ public ChangeEntry(Context context) {
+ this(context, null, 0);
+ }
+
+ public ChangeEntry(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ChangeEntry(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ inflate(context, R.layout.change_entry, this);
+ }
+
+ public void init(ReviewItApp app, Change change) {
+ ((ProjectBranchTopicAgeView)findViewById(R.id.projectBranchTopicAge))
+ .init(change);
+ ((UserView)findViewById(R.id.owner)).init(app, change.info.owner);
+
+ ChangeInfo info = change.info;
+ WidgetUtil.setText(findViewById(R.id.subject), info.subject);
+ }
+}
diff --git a/app/src/main/res/layout/change_entry.xml b/app/src/main/res/layout/change_entry.xml
new file mode 100644
index 0000000..411470d
--- /dev/null
+++ b/app/src/main/res/layout/change_entry.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="3dp"
+ android:paddingTop="3dp"
+ android:paddingRight="3dp"
+ android:paddingBottom="3dp">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+
+ <com.google.reviewit.widget.ProjectBranchTopicAgeView
+ android:id="@+id/projectBranchTopicAge"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:id="@+id/subject"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <com.google.reviewit.widget.UserView
+ android:id="@+id/owner"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:textSize="10sp"
+ app:avatarSize="15dp"/>
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_sort_settings.xml b/app/src/main/res/layout/content_query_settings.xml
similarity index 100%
rename from app/src/main/res/layout/content_sort_settings.xml
rename to app/src/main/res/layout/content_query_settings.xml
diff --git a/app/src/main/res/layout/content_review_changes.xml b/app/src/main/res/layout/content_review_changes.xml
index 456ce76..3851a97 100644
--- a/app/src/main/res/layout/content_review_changes.xml
+++ b/app/src/main/res/layout/content_review_changes.xml
@@ -15,14 +15,47 @@
limitations under the License. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <TextView
+ <include layout="@layout/progress"/>
+
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:textSize="40sp"
- android:text="TODO"/>
-</LinearLayout>
\ No newline at end of file
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/changeList"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/statusText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:layout_marginTop="15dp"
+ android:textSize="24sp"
+ android:text="@string/loading"/>
+
+ <ProgressBar
+ android:id="@+id/initialProgress"
+ android:layout_marginTop="20dp"
+ android:layout_width="match_parent"
+ android:layout_height="150dp"
+ android:indeterminate="true"/>
+
+ <ImageView
+ android:id="@+id/reloadButton"
+ android:layout_width="match_parent"
+ android:layout_height="150dp"
+ android:layout_marginTop="20dp"
+ android:gravity="center_horizontal"
+ android:clickable="true"
+ android:src="@drawable/ic_refresh_black_48dp"
+ android:visibility="gone"/>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/app/src/main/res/layout/content_settings.xml b/app/src/main/res/layout/content_settings.xml
index 41bd70a..78eecf8 100644
--- a/app/src/main/res/layout/content_settings.xml
+++ b/app/src/main/res/layout/content_settings.xml
@@ -49,10 +49,10 @@
android:layout_marginBottom="10dp"/>
<TextView
- android:id="@+id/sortConfig"
+ android:id="@+id/queryConfig"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/sortConfig"
+ android:text="@string/queryConfig"
android:gravity="center_horizontal"
android:textSize="20sp"/>
</LinearLayout>
diff --git a/app/src/main/res/menu/menu_review_changes.xml b/app/src/main/res/menu/menu_review_changes.xml
new file mode 100644
index 0000000..af11e52
--- /dev/null
+++ b/app/src/main/res/menu/menu_review_changes.xml
@@ -0,0 +1,22 @@
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/action_reload_query"
+ android:orderInCategory="100"
+ android:title="@string/action_reload_query"
+ app:showAsAction="never"/>
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 68e7525..c4de3bc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -40,6 +40,9 @@
<string name="action_restore">Restore...</string>
<string name="action_undo">Undo</string>
+ <!-- ReviewChangesFragment -->
+ <string name="no_changes_match">No changes match the query!</string>
+
<!-- ErrorFragment -->
<string name="title_activity_error">Error</string>
@@ -131,7 +134,7 @@
<!-- SettingsFragment -->
<string name="serverConfig">Server Configuration</string>
- <string name="sortConfig">Sort Configuration</string>
+ <string name="queryConfig">Query Configuration</string>
<string name="add_server">Add Server</string>
<string name="connection_failed">Connection failed: %1$s</string>