/* * 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.mobile.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.mobile.Intents.EXTRA_COMMENT; import static com.github.mobile.Intents.EXTRA_GIST_ID; import static com.github.mobile.RequestCodes.COMMENT_CREATE; 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.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.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.github.kevinsawicki.wishlist.ViewUtils; import com.github.mobile.R.id; import com.github.mobile.R.layout; import com.github.mobile.R.menu; import com.github.mobile.R.string; import com.github.mobile.accounts.AccountUtils; import com.github.mobile.core.OnLoadListener; import com.github.mobile.core.gist.FullGist; import com.github.mobile.core.gist.GistStore; import com.github.mobile.core.gist.RefreshGistTask; import com.github.mobile.core.gist.StarGistTask; import com.github.mobile.core.gist.UnstarGistTask; import com.github.mobile.ui.DialogFragment; import com.github.mobile.ui.HeaderFooterListAdapter; import com.github.mobile.ui.StyledText; import com.github.mobile.ui.comment.CommentListAdapter; import com.github.mobile.util.AvatarLoader; import com.github.mobile.util.HttpImageGetter; import com.github.mobile.util.ShareUtils; import com.github.mobile.util.ToastUtils; import com.github.mobile.util.TypefaceUtils; import com.google.inject.Inject; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.eclipse.egit.github.core.Comment; import org.eclipse.egit.github.core.Gist; import org.eclipse.egit.github.core.GistFile; import org.eclipse.egit.github.core.User; /** * Activity to display an existing Gist */ public class GistFragment extends DialogFragment implements OnItemClickListener { private String gistId; private List<Comment> 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<View>(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gistId = getArguments().getString(EXTRA_GIST_ID); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(layout.comment_list, null); headerView = inflater.inflate(layout.gist_header, null); created = (TextView) headerView.findViewById(id.tv_gist_creation); updated = (TextView) headerView.findViewById(id.tv_gist_updated); description = (TextView) headerView .findViewById(id.tv_gist_description); loadingView = inflater.inflate(layout.loading_item, null); ((TextView) loadingView.findViewById(id.tv_loading)) .setText(string.loading_comments); footerView = inflater.inflate(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(id.pb_loading); Activity activity = getActivity(); adapter = new HeaderFooterListAdapter<CommentListAdapter>(list, new CommentListAdapter(activity.getLayoutInflater(), avatars, imageGetter)); list.setAdapter(adapter); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); list.setOnItemClickListener(this); adapter.addHeader(headerView); adapter.addFooter(footerView); gist = store.getGist(gistId); if (gist != null) { updateHeader(gist); updateFiles(gist); } if (gist == null || (gist.getComments() > 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.getUser(); if (user == null) return false; String login = AccountUtils.getLogin(getActivity()); return login != null && login.equals(user.getLogin()); } private void updateHeader(Gist gist) { Date createdAt = gist.getCreatedAt(); if (createdAt != null) { StyledText text = new StyledText(); text.append(getString(string.prefix_created)); text.append(createdAt); created.setText(text); created.setVisibility(VISIBLE); } else created.setVisibility(GONE); Date updatedAt = gist.getUpdatedAt(); if (updatedAt != null && !updatedAt.equals(createdAt)) { StyledText text = new StyledText(); text.append(getString(string.prefix_updated)); text.append(updatedAt); updated.setText(text); updated.setVisibility(VISIBLE); } else updated.setVisibility(GONE); String desc = gist.getDescription(); if (!TextUtils.isEmpty(desc)) description.setText(desc); else description.setText(string.no_description_given); ViewUtils.setGone(progress, true); ViewUtils.setGone(list, false); } @Override public void onCreateOptionsMenu(Menu options, MenuInflater inflater) { inflater.inflate(menu.gist_view, options); } @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); boolean owner = isOwner(); if (!owner) { menu.removeItem(id.m_delete); MenuItem starItem = menu.findItem(id.m_star); starItem.setEnabled(loadFinished && !owner); if (starred) starItem.setTitle(string.unstar); else starItem.setTitle(string.star); } else menu.removeItem(id.m_star); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (gist == null) return super.onOptionsItemSelected(item); switch (item.getItemId()) { case id.m_comment: startActivityForResult(CreateCommentActivity.createIntent(gist), COMMENT_CREATE); return true; case id.m_star: if (starred) unstarGist(); else starGist(); return true; case id.m_refresh: refreshGist(); return true; case id.m_share: shareGist(); return true; default: return super.onOptionsItemSelected(item); } } private void starGist() { ToastUtils.show(getActivity(), 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.getId(); subject.append(id); User user = gist.getUser(); if (user != null && !TextUtils.isEmpty(user.getLogin())) subject.append(" by ").append(user.getLogin()); startActivity(ShareUtils.create(subject, "https://gist.github.com/" + id)); } private void unstarGist() { ToastUtils.show(getActivity(), 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 && COMMENT_CREATE == requestCode && data != null) { Comment comment = (Comment) data .getSerializableExtra(EXTRA_COMMENT); if (comments != null) { comments.add(comment); gist.setComments(gist.getComments() + 1); 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.getFiles(); 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(layout.gist_file_item, null); ((TextView) fileView.findViewById(id.tv_file)).setText(file .getFilename()); ((TextView) fileView.findViewById(id.tv_file_icon)) .setTypeface(octicons); adapter.addHeader(fileView, file, true); fileHeaders.add(fileView); } } private void updateList(Gist gist, List<Comment> comments) { adapter.getWrappedAdapter().setItems( comments.toArray(new Comment[comments.size()])); adapter.removeHeader(loadingView); headerView.setVisibility(VISIBLE); updateHeader(gist); updateFiles(gist); } private void refreshGist() { getSherlockActivity().setSupportProgressBarIndeterminateVisibility(true); new RefreshGistTask(getActivity(), gistId, imageGetter) { @Override protected void onException(Exception e) throws RuntimeException { super.onException(e); getSherlockActivity().setSupportProgressBarIndeterminateVisibility(false); ToastUtils.show(getActivity(), e, 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); getSherlockActivity().setSupportProgressBarIndeterminateVisibility(false); } }.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)); } }