/*
* Copyright (c) 2015 PocketHub
*
* 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.android.ui.repo;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import com.afollestad.materialdialogs.MaterialDialog;
import com.meisolsson.githubsdk.core.ServiceGenerator;
import com.meisolsson.githubsdk.model.Repository;
import com.meisolsson.githubsdk.model.User;
import com.github.pockethub.android.Intents.Builder;
import com.github.pockethub.android.R;
import com.github.pockethub.android.core.repo.RepositoryUtils;
import com.github.pockethub.android.ui.TabPagerActivity;
import com.github.pockethub.android.ui.user.UriLauncherActivity;
import com.github.pockethub.android.ui.user.UserViewActivity;
import com.github.pockethub.android.util.AvatarLoader;
import com.github.pockethub.android.util.InfoUtils;
import com.github.pockethub.android.util.ShareUtils;
import com.github.pockethub.android.util.ToastUtils;
import com.meisolsson.githubsdk.service.activity.StarringService;
import com.meisolsson.githubsdk.service.repositories.RepositoryContentService;
import com.meisolsson.githubsdk.service.repositories.RepositoryForkService;
import com.meisolsson.githubsdk.service.repositories.RepositoryService;
import com.google.inject.Inject;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Response;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static com.github.pockethub.android.Intents.EXTRA_REPOSITORY;
import static com.github.pockethub.android.ResultCodes.RESOURCE_CHANGED;
import static com.github.pockethub.android.ui.view.OcticonTextView.ICON_CODE;
import static com.github.pockethub.android.ui.view.OcticonTextView.ICON_COMMIT;
import static com.github.pockethub.android.ui.view.OcticonTextView.ICON_ISSUE_OPEN;
import static com.github.pockethub.android.ui.view.OcticonTextView.ICON_NEWS;
/**
* Activity to view a repository
*/
public class RepositoryViewActivity extends TabPagerActivity<RepositoryPagerAdapter> {
public static final String TAG = "RepositoryViewActivity";
/**
* Create intent for this activity
*
* @param repository
* @return intent
*/
public static Intent createIntent(Repository repository) {
return new Builder("repo.VIEW").repo(repository).toIntent();
}
private Repository repository;
@Inject
private AvatarLoader avatars;
private ProgressBar loadingBar;
private boolean isStarred;
private boolean starredStatusChecked;
private boolean hasReadme;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
repository = getParcelableExtra(EXTRA_REPOSITORY);
loadingBar = (ProgressBar) findViewById(R.id.pb_loading);
User owner = repository.owner();
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle(repository.name());
actionBar.setSubtitle(owner.login());
actionBar.setDisplayHomeAsUpEnabled(true);
if (owner.avatarUrl() != null && RepositoryUtils.isComplete(repository)) {
checkReadme();
} else {
avatars.bind(getSupportActionBar(), owner);
loadingBar.setVisibility(View.VISIBLE);
setGone(true);
ServiceGenerator.createService(this, RepositoryService.class)
.getRepository(repository.owner().login(), repository.name())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.bindToLifecycle())
.subscribe(response -> {
repository = response.body();
checkReadme();
}, e -> {
ToastUtils.show(this, R.string.error_repo_load);
loadingBar.setVisibility(View.GONE);
});
}
}
@Override
public boolean onCreateOptionsMenu(Menu optionsMenu) {
getMenuInflater().inflate(R.menu.activity_repository, optionsMenu);
return super.onCreateOptionsMenu(optionsMenu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem followItem = menu.findItem(R.id.m_star);
followItem.setVisible(starredStatusChecked);
followItem.setTitle(isStarred ? R.string.unstar : R.string.star);
return super.onPrepareOptionsMenu(menu);
}
@Override
public void onBackPressed() {
if (adapter == null || pager.getCurrentItem() != adapter.getItemCode() || !adapter.onBackPressed()) {
super.onBackPressed();
}
}
private void checkReadme() {
loadingBar.setVisibility(View.VISIBLE);
ServiceGenerator.createService(this, RepositoryContentService.class)
.hasReadme(repository.owner().login(), repository.name())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.<Response>bindToLifecycle())
.subscribe(response -> {
hasReadme = response.code() == 200;
configurePager();
}, e -> {
hasReadme = false;
configurePager();
});
}
private void configurePager() {
avatars.bind(getSupportActionBar(), repository.owner());
configureTabPager();
loadingBar.setVisibility(View.GONE);
setGone(false);
checkStarredRepositoryStatus();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.m_star:
starRepository();
return true;
case R.id.m_fork:
forkRepository();
return true;
case R.id.m_contributors:
startActivity(RepositoryContributorsActivity.createIntent(repository));
return true;
case R.id.m_share:
shareRepository();
return true;
case R.id.m_delete:
deleteRepository();
return true;
case R.id.m_refresh:
checkStarredRepositoryStatus();
return super.onOptionsItemSelected(item);
case android.R.id.home:
finish();
Intent intent = UserViewActivity.createIntent(repository.owner());
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onDialogResult(int requestCode, int resultCode, Bundle arguments) {
adapter.onDialogResult(pager.getCurrentItem(), requestCode, resultCode, arguments);
}
@Override
protected RepositoryPagerAdapter createAdapter() {
return new RepositoryPagerAdapter(this, repository.hasIssues(), hasReadme);
}
@Override
protected int getContentView() {
return R.layout.tabbed_progress_pager;
}
@Override
protected String getIcon(int position) {
switch (position) {
case 0:
return ICON_NEWS;
case 1:
return ICON_CODE;
case 2:
return ICON_COMMIT;
case 3:
return ICON_ISSUE_OPEN;
default:
return super.getIcon(position);
}
}
private void starRepository() {
StarringService service = ServiceGenerator.createService(this, StarringService.class);
Single<Response<Boolean>> starSingle;
if (isStarred) {
starSingle = service.unstarRepository(repository.owner().login(), repository.name());
} else {
starSingle = service.starRepository(repository.owner().login(), repository.name());
}
starSingle.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.bindToLifecycle())
.subscribe(aBoolean -> {
isStarred = !isStarred;
setResult(RESOURCE_CHANGED);
}, e -> ToastUtils.show(this, isStarred ? R.string.error_unstarring_repository : R.string.error_starring_repository));
}
private void checkStarredRepositoryStatus() {
starredStatusChecked = false;
ServiceGenerator.createService(this, StarringService.class)
.checkIfRepositoryIsStarred(repository.owner().login(), repository.name())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.bindToLifecycle())
.subscribe(response -> {
isStarred = response.code() == 204;
starredStatusChecked = true;
invalidateOptionsMenu();
});
}
private void shareRepository() {
String repoUrl = repository.htmlUrl();
if (TextUtils.isEmpty(repoUrl)) {
repoUrl = "https://github.com/" + InfoUtils.createRepoId(repository);
}
Intent sharingIntent = ShareUtils.create(InfoUtils.createRepoId(repository), repoUrl);
startActivity(sharingIntent);
}
private void forkRepository() {
ServiceGenerator.createService(this, RepositoryForkService.class)
.createFork(repository.owner().login(), repository.name())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.bindToLifecycle())
.subscribe(response -> {
Repository repo = response.body();
UriLauncherActivity.launchUri(this, Uri.parse(repo.htmlUrl()));
}, e -> ToastUtils.show(this, R.string.error_forking_repository));
}
private void deleteRepository() {
new MaterialDialog.Builder(this)
.title(R.string.are_you_sure)
.content(R.string.unexpected_bad_things)
.positiveText(R.string.not_sure)
.negativeText(R.string.delete_cap)
.callback(new MaterialDialog.ButtonCallback() {
@Override
public void onPositive(MaterialDialog dialog) {
super.onPositive(dialog);
dialog.dismiss();
}
@Override
public void onNegative(MaterialDialog dialog) {
super.onNegative(dialog);
dialog.dismiss();
ServiceGenerator.createService(dialog.getContext(), RepositoryService.class)
.deleteRepository(repository.owner().login(), repository.name())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(RepositoryViewActivity.this.bindToLifecycle())
.subscribe(response -> {
onBackPressed();
ToastUtils.show(RepositoryViewActivity.this, R.string.delete_successful);
}, e -> ToastUtils.show(RepositoryViewActivity.this, R.string.error_deleting_repository));
}
})
.show();
}
}