Java tutorial
// 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.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.LayoutRes; import android.support.v4.app.Fragment; 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 { widgetUtil.toast(R.string.reviewer_added); 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; } } }