package com.alorma.github.ui.activity;
import android.Manifest;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v7.app.NotificationCompat;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.alorma.github.R;
import com.alorma.github.cache.CacheWrapper;
import com.alorma.github.emoji.Emoji;
import com.alorma.github.emoji.EmojisActivity;
import com.alorma.github.sdk.bean.info.IssueInfo;
import com.alorma.github.sdk.bean.info.RepoInfo;
import com.alorma.github.ui.activity.base.RepositoryThemeActivity;
import com.alorma.github.ui.utils.ContentEditorText;
import com.alorma.github.ui.utils.DialogUtils;
import com.alorma.github.ui.utils.IntentHelper;
import com.alorma.github.ui.utils.uris.UriUtils;
import com.alorma.github.utils.AttributesUtils;
import com.github.mobile.util.HtmlUtils;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.single.EmptyPermissionListener;
import com.karumi.dexter.listener.single.PermissionListener;
import com.linkedin.android.spyglass.mentions.MentionsEditable;
import com.linkedin.android.spyglass.tokenization.QueryToken;
import com.linkedin.android.spyglass.tokenization.interfaces.QueryTokenReceiver;
import com.linkedin.android.spyglass.ui.RichEditorView;
import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.octicons_typeface_library.Octicons;
import imgurapiexample.services.ImgurUpload;
import java.io.File;
import java.util.Collections;
import java.util.List;
import rx.Scheduler;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class ContentEditorActivity extends RepositoryThemeActivity
implements Toolbar.OnMenuItemClickListener, QueryTokenReceiver, ContentEditorPresenter.Callback {
public static final String CONTENT = "CONTENT";
private static final String HINT = "HINT";
private static final String PREFILL = "PREFILL";
private static final String REPO_INFO = "REPO_INFO";
private static final String ISSUE_NUM = "ISSUE_NUM";
private static final String ALLOW_EMPTY = "ALLOW_EMPTY";
private static final String BACK_IS_OK = "BACK_IS_OK";
public static final String PARCELABLE = "PARCELABLE";
private static final int EMOJI_REQUEST = 1515;
private RichEditorView editText;
private Toolbar toolbarExtra;
private boolean allowEmpty;
private boolean backIsOk;
private IssueInfo issueInfo;
private boolean applied = false;
private ContentEditorPresenter contentEditorPresenter;
public static Intent createLauncherIntent(Context context, String hint, String prefill, boolean allowEmpty, boolean backIsOk) {
Intent intent = new Intent(context, ContentEditorActivity.class);
if (hint != null) {
intent.putExtra(HINT, hint);
}
if (prefill != null) {
intent.putExtra(PREFILL, prefill);
}
intent.putExtra(ALLOW_EMPTY, allowEmpty);
intent.putExtra(BACK_IS_OK, backIsOk);
return intent;
}
public static Intent createLauncherIntent(Context context, RepoInfo repoInfo, int issueNum, String hint, String prefill,
boolean allowEmpty, boolean backIsOk) {
Intent intent = new Intent(context, ContentEditorActivity.class);
if (hint != null) {
intent.putExtra(HINT, hint);
}
if (prefill != null) {
intent.putExtra(PREFILL, prefill);
}
if (repoInfo != null) {
intent.putExtra(REPO_INFO, repoInfo);
}
intent.putExtra(ISSUE_NUM, issueNum);
intent.putExtra(ALLOW_EMPTY, allowEmpty);
intent.putExtra(BACK_IS_OK, backIsOk);
return intent;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_editor);
if (getIntent().getExtras() != null) {
findViews();
Scheduler observeOn = AndroidSchedulers.mainThread();
Scheduler subscribeOn = Schedulers.io();
contentEditorPresenter = new ContentEditorPresenter(getString(R.string.imgur_client_id), new ImgurUpload(), observeOn, subscribeOn);
if (getSupportActionBar() != null) {
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(AttributesUtils.getPrimaryColor(this)));
}
toolbarExtra.inflateMenu(R.menu.content_editor_extra);
toolbarExtra.setOnMenuItemClickListener(this);
final String hint = getIntent().getExtras().getString(HINT);
if (!TextUtils.isEmpty(hint)) {
editText.setHint(hint);
} else {
editText.setHint(getString(R.string.edit_hint));
}
final String prefill = getIntent().getExtras().getString(PREFILL);
if (!TextUtils.isEmpty(prefill)) {
editText.setText(prefill);
}
editText.setQueryTokenReceiver(this);
if (issueInfo != null) {
String issueComment = CacheWrapper.getIssueComment(issueInfo.toString());
if (issueComment != null) {
editText.setText(formatText(issueComment));
}
}
String content = getIntent().getExtras().getString(PREFILL);
if (getIntent().getExtras().containsKey(REPO_INFO) && getIntent().getExtras().containsKey(ISSUE_NUM)) {
RepoInfo repoInfo = getIntent().getExtras().getParcelable(REPO_INFO);
int issueNumber = getIntent().getExtras().getInt(ISSUE_NUM);
issueInfo = new IssueInfo();
issueInfo.repoInfo = repoInfo;
issueInfo.num = issueNumber;
if (!TextUtils.isEmpty(content)) {
editText.setText(formatText(content));
}
}
allowEmpty = getIntent().getExtras().getBoolean(ALLOW_EMPTY, false);
if (!allowEmpty) {
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
invalidateOptionsMenu();
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (hint != null) {
if (editText.getText().length() > 0) {
setTitle(hint);
}
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
backIsOk = getIntent().getExtras().getBoolean(BACK_IS_OK, false);
} else {
finish();
}
}
private String formatText(String source) {
return HtmlUtils.format(source).toString();
}
private void findViews() {
editText = (RichEditorView) findViewById(R.id.edit);
toolbarExtra = (Toolbar) findViewById(R.id.toolbarExtra);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.content_editor, menu);
MenuItem okItem = menu.findItem(R.id.action_ok);
if (okItem != null) {
IconicsDrawable iconicsDrawable = new IconicsDrawable(this, Octicons.Icon.oct_check).actionBar().color(Color.WHITE);
okItem.setIcon(iconicsDrawable);
}
MenuItem trashItem = menu.findItem(R.id.action_trash);
if (okItem != null) {
IconicsDrawable iconicsDrawable = new IconicsDrawable(this, Octicons.Icon.oct_trashcan).actionBar().color(Color.WHITE);
trashItem.setIcon(iconicsDrawable);
}
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem okItem = menu.findItem(R.id.action_ok);
okItem.setEnabled(allowEmpty || !TextUtils.isEmpty(editText.getText()));
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.action_ok:
returnContent();
break;
case R.id.action_trash:
editText.setText("");
if (issueInfo != null) {
CacheWrapper.clearIssueComment(issueInfo.toString());
}
break;
case R.id.add_content_editor_emojis:
Intent intentEmojis = new Intent(this, EmojisActivity.class);
startActivityForResult(intentEmojis, EMOJI_REQUEST);
break;
case R.id.add_content_editor_source:
StringBuilder builder = new StringBuilder();
builder.append(" ```");
builder.append("\n");
builder.append("\n");
builder.append(" ```");
appendText(builder.toString());
editText.setSelection(editText.getText().length() - 5);
break;
case R.id.add_content_editor_picture:
showAddPicture();
break;
}
return true;
}
private void showAddPicture() {
MaterialDialog.Builder builder = new DialogUtils().builder(this);
builder.title(R.string.add_image_title);
builder.negativeText(R.string.add_image_by_link);
builder.onNegative((dialog1, which) -> showImageLink());
builder.positiveText(R.string.add_image_by_upload);
builder.onPositive((dialog1, which) -> showImageUploadPicker());
builder.show();
}
private void showImageLink() {
tracker.trackEvent("UPLOAD_IMAGE", "type", "link");
new DialogUtils().builder(this)
.title(R.string.addPicture)
.content(R.string.addPictureContent)
.input(R.string.addPictureHint, 0, false, (materialDialog, charSequence) -> {
MentionsEditable text = editText.getText();
String textForImage = new ContentEditorText().getTextForImage(charSequence.toString());
text.append(textForImage);
})
.neutralText(R.string.cancel)
.show();
}
private void showImageUploadPicker() {
tracker.trackEvent("UPLOAD_IMAGE", "type", "upload");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
PermissionListener permissionListener = new EmptyPermissionListener() {
@Override
public void onPermissionGranted(PermissionGrantedResponse response) {
IntentHelper.chooseFileIntent(ContentEditorActivity.this);
}
};
Dexter.checkPermission(permissionListener, Manifest.permission.READ_EXTERNAL_STORAGE);
} else {
IntentHelper.chooseFileIntent(this);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
switch (requestCode) {
case EMOJI_REQUEST:
Emoji emoji = data.getParcelableExtra(EmojisActivity.EMOJI);
appendText(":" + emoji.getKey() + ":");
break;
case IntentHelper.FILE_PICK:
String path = UriUtils.getPath(this, data.getData());
if (path != null) {
File file = new File(path);
contentEditorPresenter.setCallback(this);
contentEditorPresenter.uploadImageWithImgurAPI(file);
}
break;
}
}
}
@Override
protected void close(boolean navigateUp) {
saveCache();
if (!allowEmpty) {
finish();
} else {
returnContent();
}
}
private void returnContent() {
int result = RESULT_CANCELED;
if (!TextUtils.isEmpty(editText.getText())) {
result = RESULT_OK;
}
if (backIsOk) {
result = RESULT_OK;
}
Intent getIntent = getIntent();
Parcelable parcelable = getIntent.getParcelableExtra(PARCELABLE);
Intent intent = new Intent();
intent.putExtra(CONTENT, editText.getText().toString());
if (parcelable != null) {
intent.putExtra(PARCELABLE, parcelable);
}
if (issueInfo != null) {
applied = true;
CacheWrapper.clearIssueComment(issueInfo.toString());
}
setResult(result, intent);
finish();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
onOptionsItemSelected(item);
return true;
}
@Override
public void onStart() {
super.onStart();
contentEditorPresenter.setCallback(this);
}
@Override
public void onStop() {
saveCache();
contentEditorPresenter.setCallback(null);
super.onStop();
}
private void saveCache() {
if (!applied && issueInfo != null) {
try {
CacheWrapper.setNewIssueComment(issueInfo.toString(), editText.getText().toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public List<String> onQueryReceived(@NonNull final QueryToken queryToken) {
/* TODO
if (!queryToken.getKeywords().startsWith("@")) {
final List<String> buckets = new ArrayList<>();
buckets.add("github");
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(queryToken.getKeywords());
}
}
})
.filter(s -> queryToken.getTokenString().startsWith("@") && queryToken.getTokenString().length() > 2)
.map(s -> s.replaceFirst("@", ""))
.flatMap(s -> {
Observable<List<User>> search = new UsersSearchClient(s).observable()
.delay(200, TimeUnit.MILLISECONDS)
.map(new Func1<Pair<List<User>, Integer>, List<User>>() {
@Override
public List<User> call(Pair<List<User>, Integer> listIntegerPair) {
return listIntegerPair.first;
}
})
.delay(2, TimeUnit.SECONDS);
Observable<List<User>> contributors = new GetRepoContributorsClient(issueInfo.repoInfo).observable().map(contributors1 -> {
List<User> users = new ArrayList<>();
for (Contributor contributor : contributors1) {
if (contributor.author.getLogin().contains(s)) {
users.add(contributor.author);
}
}
return users;
});
return Observable.concat(contributors, search);
})
.map(users -> {
List<SearchableUser> searchableUsers = new ArrayList<>();
for (User user : users) {
SearchableUser searchableUser = new SearchableUser();
searchableUser.id = user.id;
searchableUser.login = user.login;
searchableUsers.add(searchableUser);
}
return searchableUsers;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(users -> editText.onReceiveSuggestionsResult(new SuggestionsResult(queryToken, users), "github"), throwable -> {
}, () -> {
});
return buckets;
}
*/
return Collections.emptyList();
}
@Override
public void showImageLoading(String imageName) {
Toast.makeText(ContentEditorActivity.this, R.string.imgur_uploading_image_title, Toast.LENGTH_SHORT).show();
NotificationCompat.Builder builder = getImageNotificationBuilder(imageName);
builder.setProgress(100, 50, true);
builder.setOngoing(true);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(imageName.hashCode(), builder.build());
tracker.trackEvent("UPLOAD_IMAGE", "status", "start");
}
@NonNull
private NotificationCompat.Builder getImageNotificationBuilder(String imageName) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setColor(AttributesUtils.getPrimaryColor(this));
builder.setSmallIcon(R.drawable.ic_stat_name);
builder.setContentTitle(getString(R.string.imgur_uploading_image_title));
builder.setContentText(getString(R.string.imgur_uploading_image_text, imageName));
return builder;
}
@Override
public void appendText(String text) {
runOnUiThread(() -> {
Editable mentionsEditable = editText.getText();
EditText editTextInner = (EditText) editText.findViewById(R.id.text_editor);
mentionsEditable.insert(editTextInner.getSelectionStart(), text);
});
}
@Override
public void showImageUploadError(String imageName) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(imageName.hashCode());
tracker.trackEvent("UPLOAD_IMAGE", "status", "error");
}
@Override
public void onImageUploaded(String imageName, String link) {
NotificationCompat.Builder builder = getImageNotificationBuilder(imageName);
builder.setContentTitle(getString(R.string.imgur_uploading_image_title_done));
Intent openPhotoIntent = new Intent(Intent.ACTION_VIEW);
openPhotoIntent.setData(Uri.parse(link));
PendingIntent openIntent = PendingIntent.getActivity(this, 1234, openPhotoIntent, 0);
builder.addAction(0, getString(R.string.imgur_uploading_image_action_open), openIntent);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(imageName.hashCode(), builder.build());
tracker.trackEvent("UPLOAD_IMAGE", "status", "complete");
}
}