| // 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; |
| |
| import android.app.Fragment; |
| import android.content.Context; |
| import android.os.AsyncTask; |
| import android.os.Bundle; |
| import android.support.annotation.LayoutRes; |
| import android.util.Log; |
| import android.util.TypedValue; |
| import android.view.KeyEvent; |
| import android.view.inputmethod.EditorInfo; |
| import android.widget.ArrayAdapter; |
| import android.widget.AutoCompleteTextView; |
| import android.widget.Filter; |
| import android.widget.Filterable; |
| import android.widget.ImageView; |
| import android.widget.TableLayout; |
| import android.widget.TableRow; |
| import android.widget.TextView; |
| |
| import com.google.gerrit.extensions.common.AccountInfo; |
| import com.google.gerrit.extensions.restapi.RestApiException; |
| import com.google.reviewit.app.Change; |
| import com.google.reviewit.util.ChangeUtil; |
| import com.google.reviewit.widget.ChangeBox; |
| import com.google.reviewit.util.FormatUtil; |
| import com.google.reviewit.util.WidgetUtil; |
| import com.urswolfer.gerrit.client.rest.http.HttpStatusException; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import static com.google.reviewit.util.LayoutUtil.matchAndWrapTableLayout; |
| import static com.google.reviewit.util.LayoutUtil.matchAndWrapTableRowLayout; |
| import static com.google.reviewit.util.LayoutUtil.wrapTableRowLayout; |
| |
| /** |
| * Fragment to add a reviewer to a change. |
| * On typing reviewer names are auto-completed. |
| */ |
| public class AddReviewerFragment extends BaseFragment |
| implements OnBackPressedAware { |
| private static final String TAG = AddReviewerFragment.class.getName(); |
| private static final String ORIGIN = |
| "com.google.reviewit.AddReviewerFragment.ORIGIN"; |
| |
| public static AddReviewerFragment create(Class<? extends Fragment> origin) { |
| AddReviewerFragment fragment = new AddReviewerFragment(); |
| Bundle bundle = new Bundle(); |
| bundle.putSerializable(ORIGIN, origin); |
| fragment.setArguments(bundle); |
| return fragment; |
| } |
| |
| @Override |
| protected @LayoutRes int getLayout() { |
| return R.layout.content_add_reviewer; |
| } |
| |
| @Override |
| public void onActivityCreated(Bundle savedInstanceState) { |
| super.onActivityCreated(savedInstanceState); |
| |
| Change change = getApp().getSortActionHandler().getCurrentChange(); |
| initInputField(change); |
| try { |
| displayReviewers(change); |
| displayCCs(change); |
| ChangeUtil.colorBackground(root, change); |
| ((ChangeBox) v(R.id.changeBox)).display(getApp(), change); |
| } catch (Throwable t) { |
| Log.e(TAG, "Failed to display change", t); |
| display(ErrorFragment.create(t)); |
| } |
| } |
| |
| private void initInputField(final Change change) { |
| AutoCompleteTextView editText = |
| (AutoCompleteTextView) v(R.id.reviewerInput); |
| editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { |
| @Override |
| public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { |
| boolean handled = false; |
| if (actionId == EditorInfo.IME_ACTION_SEND) { |
| addReviewer(change, v.getText().toString()); |
| handled = true; |
| } |
| return handled; |
| } |
| }); |
| editText.setAdapter(new SuggestReviewerAdapter(getContext())); |
| } |
| |
| private void addReviewer(Change change, final String reviewerId) { |
| new AsyncTask<Change, Void, String>() { |
| @Override |
| protected String doInBackground(Change... changes) { |
| Change change = changes[0]; |
| try { |
| change.addReviewer(reviewerId); |
| return null; |
| } catch (RestApiException e) { |
| Log.w(TAG, "Adding reviewer failed", e); |
| if (e instanceof HttpStatusException) { |
| HttpStatusException se = (HttpStatusException) e; |
| return getString(R.string.add_reviewer_error, se.getStatusCode(), |
| se.getStatusText()); |
| } else { |
| return e.getMessage(); |
| } |
| } |
| } |
| |
| protected void onPostExecute(String errorMsg) { |
| if (errorMsg != null) { |
| widgetUtil.showError(errorMsg); |
| } else { |
| AddReviewerFragment fragment = new AddReviewerFragment(); |
| Bundle bundle = new Bundle(); |
| bundle.putAll(getArguments()); |
| fragment.setArguments(bundle); |
| display(fragment, false); |
| } |
| } |
| }.execute(change); |
| } |
| |
| |
| private void displayReviewers(Change change) { |
| TableLayout tl = (TableLayout) v(R.id.reviewerTable); |
| Collection<AccountInfo> reviewers = change.reviewers(false); |
| if (!reviewers.isEmpty()) { |
| for (AccountInfo reviewer : reviewers) { |
| addReviewerRow(tl, reviewer); |
| } |
| } else { |
| WidgetUtil.setText(v(R.id.reviewersLabel), |
| getString(R.string.no_reviewers)); |
| } |
| } |
| |
| private void displayCCs(Change change) { |
| TableLayout tl = (TableLayout) v(R.id.reviewerTable); |
| Collection<AccountInfo> ccs = change.ccs(); |
| if (!ccs.isEmpty()) { |
| TableRow tr = new TableRow(getContext()); |
| tr.setLayoutParams(matchAndWrapTableRowLayout()); |
| TextView ccsTitle = new TextView(getContext()); |
| TableRow.LayoutParams params = wrapTableRowLayout(2); |
| params.bottomMargin = widgetUtil.dpToPx(3); |
| ccsTitle.setLayoutParams(params); |
| ccsTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20); |
| ccsTitle.setText(getString(R.string.ccs)); |
| tr.addView(ccsTitle); |
| tl.addView(tr, matchAndWrapTableLayout()); |
| for (AccountInfo cc : ccs) { |
| addReviewerRow(tl, cc); |
| } |
| } |
| } |
| |
| private void addReviewerRow(TableLayout tl, AccountInfo reviewer) { |
| TableRow tr = new TableRow(getContext()); |
| tr.setLayoutParams(matchAndWrapTableRowLayout()); |
| ImageView avatar = new ImageView(getContext()); |
| TableRow.LayoutParams layoutParams = new TableRow.LayoutParams( |
| widgetUtil.dpToPx(20), widgetUtil.dpToPx(20)); |
| layoutParams.setMargins(0, 0, widgetUtil.dpToPx(5), widgetUtil.dpToPx(2)); |
| avatar.setLayoutParams(layoutParams); |
| |
| WidgetUtil.displayAvatar(getApp(), reviewer, avatar); |
| tr.addView(avatar); |
| TextView reviewerName = new TextView(getContext()); |
| reviewerName.setLayoutParams(wrapTableRowLayout()); |
| reviewerName.setText(FormatUtil.format(reviewer)); |
| tr.addView(reviewerName); |
| tl.addView(tr, matchAndWrapTableLayout()); |
| } |
| |
| @Override |
| public boolean onBackPressed() { |
| display((Class<? extends Fragment>) getArguments().get(ORIGIN), |
| getArguments(), false); |
| return true; |
| } |
| |
| private class SuggestReviewerAdapter extends ArrayAdapter<String> |
| implements Filterable { |
| private List<String> suggestions; |
| |
| public SuggestReviewerAdapter(Context context) { |
| super(context, android.R.layout.simple_dropdown_item_1line); |
| suggestions = Collections.emptyList(); |
| } |
| |
| @Override |
| public int getCount() { |
| return suggestions.size(); |
| } |
| |
| @Override |
| public String getItem(int index) { |
| return suggestions.get(index); |
| } |
| |
| @Override |
| public Filter getFilter() { |
| return new Filter() { |
| @Override |
| protected FilterResults performFiltering(CharSequence constraint) { |
| FilterResults filterResults = new FilterResults(); |
| if (constraint != null) { |
| suggestions = suggest(constraint.toString()); |
| filterResults.values = suggestions; |
| filterResults.count = suggestions.size(); |
| } |
| return filterResults; |
| } |
| |
| @Override |
| protected void publishResults( |
| CharSequence constraint, FilterResults results) { |
| if (results != null && results.count > 0) { |
| notifyDataSetChanged(); |
| } else { |
| notifyDataSetInvalidated(); |
| } |
| } |
| }; |
| } |
| |
| private List<String> suggest(String text) { |
| List<String> suggestions = new ArrayList<>(); |
| try { |
| for (AccountInfo a |
| : getApp().getApi() |
| .accounts() |
| .suggestAccounts(text) |
| .withLimit(10) |
| .get()) { |
| suggestions.add(FormatUtil.format(a)); |
| } |
| } catch (RestApiException e) { |
| Log.e(TAG, "Suggesting reviewers failed", e); |
| } |
| return suggestions; |
| } |
| } |
| } |