Java tutorial
/* * Copyright 2012 GitHub Inc. * * 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.github.pockethub.ui.gist; import static android.app.Activity.RESULT_OK; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static com.github.pockethub.Intents.EXTRA_COMMENT; import static com.github.pockethub.Intents.EXTRA_GIST_ID; import static com.github.pockethub.RequestCodes.COMMENT_CREATE; import static com.github.pockethub.RequestCodes.COMMENT_DELETE; import static com.github.pockethub.RequestCodes.COMMENT_EDIT; import android.app.Activity; import android.content.Intent; import android.graphics.Typeface; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.alorma.github.sdk.bean.dto.response.GithubComment; import com.github.kevinsawicki.wishlist.ViewUtils; import com.github.pockethub.R; import com.github.pockethub.accounts.AccountUtils; import com.github.pockethub.core.OnLoadListener; import com.github.pockethub.core.gist.FullGist; import com.github.pockethub.core.gist.GistStore; import com.github.pockethub.core.gist.RefreshGistTask; import com.github.pockethub.core.gist.StarGistTask; import com.github.pockethub.core.gist.UnstarGistTask; import com.github.pockethub.ui.ConfirmDialogFragment; import com.github.pockethub.ui.DialogFragment; import com.github.pockethub.ui.HeaderFooterListAdapter; import com.github.pockethub.ui.StyledText; import com.github.pockethub.ui.comment.CommentListAdapter; import com.github.pockethub.ui.comment.DeleteCommentListener; import com.github.pockethub.ui.comment.EditCommentListener; import com.github.pockethub.util.AvatarLoader; import com.github.pockethub.util.HttpImageGetter; import com.github.pockethub.util.ShareUtils; import com.github.pockethub.util.TimeUtils; import com.github.pockethub.util.ToastUtils; import com.github.pockethub.util.TypefaceUtils; import com.google.inject.Inject; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map; import com.alorma.github.sdk.bean.dto.response.Gist; import com.alorma.github.sdk.bean.dto.response.GistFile; import com.alorma.github.sdk.bean.dto.response.User; /** * Activity to display an existing Gist */ public class GistFragment extends DialogFragment implements OnItemClickListener { private String gistId; private List<GithubComment> comments; private Gist gist; private ListView list; private ProgressBar progress; @Inject private GistStore store; @Inject private HttpImageGetter imageGetter; private View headerView; private View footerView; private TextView created; private TextView updated; private TextView description; private View loadingView; private HeaderFooterListAdapter<CommentListAdapter> adapter; private boolean starred; private boolean loadFinished; @Inject private AvatarLoader avatars; private List<View> fileHeaders = new ArrayList<>(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gistId = getArguments().getString(EXTRA_GIST_ID); gist = store.getGist(gistId); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.comment_list, container, false); headerView = inflater.inflate(R.layout.gist_header, null); created = (TextView) headerView.findViewById(R.id.tv_gist_creation); updated = (TextView) headerView.findViewById(R.id.tv_gist_updated); description = (TextView) headerView.findViewById(R.id.tv_gist_description); loadingView = inflater.inflate(R.layout.loading_item, null); ((TextView) loadingView.findViewById(R.id.tv_loading)).setText(R.string.loading_comments); footerView = inflater.inflate(R.layout.footer_separator, null); return root; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); list = finder.find(android.R.id.list); progress = finder.find(R.id.pb_loading); Activity activity = getActivity(); User user = gist.user; String userName = null; if (user != null) userName = user.login; adapter = new HeaderFooterListAdapter<>(list, new CommentListAdapter(activity.getLayoutInflater(), null, avatars, imageGetter, editCommentListener, deleteCommentListener, userName, false, null)); list.setAdapter(adapter); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); list.setOnItemClickListener(this); adapter.addHeader(headerView); adapter.addFooter(footerView); if (gist != null) { updateHeader(gist); updateFiles(gist); } if (gist == null || (gist.comments > 0 && comments == null)) adapter.addHeader(loadingView, null, false); if (gist != null && comments != null) updateList(gist, comments); else refreshGist(); } private boolean isOwner() { if (gist == null) return false; User user = gist.user; if (user == null) return false; String login = AccountUtils.getLogin(getActivity()); return login != null && login.equals(user.login); } private void updateHeader(Gist gist) { Date createdAt = TimeUtils.stringToDate(gist.created_at); if (createdAt != null) { StyledText text = new StyledText(); text.append(getString(R.string.prefix_created)); text.append(createdAt); created.setText(text); created.setVisibility(VISIBLE); } else created.setVisibility(GONE); Date updatedAt = TimeUtils.stringToDate(gist.updated_at); if (updatedAt != null && !updatedAt.equals(createdAt)) { StyledText text = new StyledText(); text.append(getString(R.string.prefix_updated)); text.append(updatedAt); updated.setText(text); updated.setVisibility(VISIBLE); } else updated.setVisibility(GONE); String desc = gist.description; if (!TextUtils.isEmpty(desc)) description.setText(desc); else description.setText(R.string.no_description_given); ViewUtils.setGone(progress, true); ViewUtils.setGone(list, false); } @Override public void onCreateOptionsMenu(Menu options, MenuInflater inflater) { inflater.inflate(R.menu.gist_view, options); } @Override public void onPrepareOptionsMenu(Menu menu) { boolean owner = isOwner(); if (!owner) { menu.removeItem(R.id.m_delete); MenuItem starItem = menu.findItem(R.id.m_star); starItem.setEnabled(loadFinished && !owner); if (starred) starItem.setTitle(R.string.unstar); else starItem.setTitle(R.string.star); } else menu.removeItem(R.id.m_star); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (gist == null) return super.onOptionsItemSelected(item); switch (item.getItemId()) { case R.id.m_comment: startActivityForResult(CreateCommentActivity.createIntent(gist), COMMENT_CREATE); return true; case R.id.m_star: if (starred) unstarGist(); else starGist(); return true; case R.id.m_refresh: refreshGist(); return true; case R.id.m_share: shareGist(); return true; default: return super.onOptionsItemSelected(item); } } private void starGist() { ToastUtils.show(getActivity(), R.string.starring_gist); new StarGistTask(getActivity(), gistId) { @Override protected void onSuccess(Gist gist) throws Exception { super.onSuccess(gist); starred = true; } @Override protected void onException(Exception e) throws RuntimeException { super.onException(e); ToastUtils.show((Activity) getContext(), e.getMessage()); } }.execute(); } private void shareGist() { StringBuilder subject = new StringBuilder("Gist "); String id = gist.id; subject.append(id); User user = gist.user; if (user != null && !TextUtils.isEmpty(user.login)) subject.append(" by ").append(user.login); startActivity(ShareUtils.create(subject, "https://gist.github.com/" + id)); } private void unstarGist() { ToastUtils.show(getActivity(), R.string.unstarring_gist); new UnstarGistTask(getActivity(), gistId) { @Override protected void onSuccess(Gist gist) throws Exception { super.onSuccess(gist); starred = false; } protected void onException(Exception e) throws RuntimeException { super.onException(e); ToastUtils.show((Activity) getContext(), e.getMessage()); } }.execute(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (RESULT_OK != resultCode || data == null) return; switch (requestCode) { case COMMENT_CREATE: GithubComment comment = (GithubComment) data.getParcelableExtra(EXTRA_COMMENT); if (comments != null) { comments.add(comment); gist.comments = gist.comments + 1; updateList(gist, comments); } else refreshGist(); return; case COMMENT_EDIT: comment = (GithubComment) data.getParcelableExtra(EXTRA_COMMENT); if (comments != null && comment != null) { int position = Collections.binarySearch(comments, comment, new Comparator<GithubComment>() { public int compare(GithubComment lhs, GithubComment rhs) { return String.valueOf(lhs.id).compareTo(rhs.id); } }); imageGetter.removeFromCache(comment.id); comments.set(position, comment); updateList(gist, comments); } else refreshGist(); return; } super.onActivityResult(requestCode, resultCode, data); } private void updateFiles(Gist gist) { final Activity activity = getActivity(); if (activity == null) return; for (View header : fileHeaders) adapter.removeHeader(header); fileHeaders.clear(); Map<String, GistFile> files = gist.files; if (files == null || files.isEmpty()) return; final LayoutInflater inflater = activity.getLayoutInflater(); final Typeface octicons = TypefaceUtils.getOcticons(activity); for (GistFile file : files.values()) { View fileView = inflater.inflate(R.layout.gist_file_item, null); ((TextView) fileView.findViewById(R.id.tv_file)).setText(file.filename); ((TextView) fileView.findViewById(R.id.tv_file_icon)).setTypeface(octicons); adapter.addHeader(fileView, file, true); fileHeaders.add(fileView); } } private void updateList(Gist gist, List<GithubComment> comments) { adapter.getWrappedAdapter().setItems(comments.toArray(new GithubComment[comments.size()])); adapter.removeHeader(loadingView); headerView.setVisibility(VISIBLE); updateHeader(gist); updateFiles(gist); } private void refreshGist() { new RefreshGistTask(getActivity(), gistId, imageGetter) { @Override protected void onException(Exception e) throws RuntimeException { super.onException(e); ToastUtils.show(getActivity(), e, R.string.error_gist_load); } @SuppressWarnings("unchecked") @Override protected void onSuccess(FullGist fullGist) throws Exception { super.onSuccess(fullGist); if (!isUsable()) return; FragmentActivity activity = getActivity(); if (activity instanceof OnLoadListener) ((OnLoadListener<Gist>) activity).loaded(fullGist.getGist()); starred = fullGist.isStarred(); loadFinished = true; gist = fullGist.getGist(); comments = fullGist; updateList(fullGist.getGist(), fullGist); } }.execute(); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Object item = parent.getItemAtPosition(position); if (item instanceof GistFile) startActivity(GistFilesViewActivity.createIntent(gist, position - 1)); } @Override public void onDialogResult(int requestCode, int resultCode, Bundle arguments) { if (RESULT_OK != resultCode) return; switch (requestCode) { case COMMENT_DELETE: final GithubComment comment = arguments.getParcelable(EXTRA_COMMENT); new DeleteCommentTask(getActivity(), gist.id, comment) { @Override protected void onSuccess(GithubComment comment) throws Exception { super.onSuccess(comment); // Update comment list if (comments != null && comment != null) { int position = Collections.binarySearch(comments, comment, new Comparator<GithubComment>() { public int compare(GithubComment lhs, GithubComment rhs) { return String.valueOf(lhs.id).compareTo(rhs.id); } }); comments.remove(position); updateList(gist, comments); } else refreshGist(); } }.start(); break; } } /** * Edit existing comment */ final EditCommentListener editCommentListener = new EditCommentListener() { public void onEditComment(GithubComment comment) { startActivityForResult(EditCommentActivity.createIntent(gist, comment), COMMENT_EDIT); } }; /** * Delete existing comment */ final DeleteCommentListener deleteCommentListener = new DeleteCommentListener() { public void onDeleteComment(GithubComment comment) { Bundle args = new Bundle(); args.putParcelable(EXTRA_COMMENT, comment); ConfirmDialogFragment.show(getActivity(), COMMENT_DELETE, getActivity().getString(R.string.confirm_comment_delete_title), getActivity().getString(R.string.confirm_comment_delete_message), args); } }; }