package im.actor.sdk.controllers.conversation.messages.content;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import com.droidkit.progress.CircularView;
import im.actor.core.entity.Message;
import im.actor.core.entity.Peer;
import im.actor.core.entity.content.DocumentContent;
import im.actor.core.entity.content.FileLocalSource;
import im.actor.core.entity.content.FileRemoteSource;
import im.actor.core.entity.content.VoiceContent;
import im.actor.core.viewmodel.FileVM;
import im.actor.core.viewmodel.FileVMCallback;
import im.actor.core.viewmodel.UploadFileVM;
import im.actor.core.viewmodel.UploadFileVMCallback;
import im.actor.runtime.actors.ActorCreator;
import im.actor.runtime.actors.ActorRef;
import im.actor.runtime.actors.ActorSystem;
import im.actor.runtime.actors.Props;
import im.actor.runtime.files.FileSystemReference;
import im.actor.sdk.ActorSDK;
import im.actor.sdk.R;
import im.actor.sdk.controllers.conversation.messages.MessagesAdapter;
import im.actor.sdk.controllers.conversation.messages.content.preprocessor.PreprocessedData;
import im.actor.sdk.core.audio.AudioPlayerActor;
import im.actor.sdk.view.TintImageView;
import static im.actor.sdk.util.ActorSDKMessenger.messenger;
import static im.actor.sdk.util.ActorSDKMessenger.myUid;
import static im.actor.sdk.util.ViewUtils.goneView;
import static im.actor.sdk.util.ViewUtils.showView;
public class AudioHolder extends MessageHolder {
private int waitColor;
private int sentColor;
private int deliveredColor;
private int readColor;
private int errorColor;
private final TintImageView stateIcon;
private final TextView time;
private final TextView duration;
private final SeekBar seekBar;
private final CircularView progressView;
private Context context;
protected ViewGroup mainContainer;
protected FrameLayout messageBubble;
protected AudioPlayerActor.AudioPlayerCallback callback;
protected String currentAudio;
protected static String currentPlayingAudio;
protected ImageView playBtn;
protected static ActorRef audioActor;
protected FileVM downloadFileVM;
protected UploadFileVM uploadFileVM;
protected long currentDuration;
protected boolean treckingTouch;
protected Handler mainThread;
public AudioHolder(MessagesAdapter adapter, final View itemView, Peer peer) {
super(adapter, itemView, false);
context = adapter.getMessagesFragment().getContext();
mainThread = new Handler(context.getMainLooper());
waitColor = ActorSDK.sharedActor().style.getConvStatePendingColor();
sentColor = ActorSDK.sharedActor().style.getConvStateSentColor();
deliveredColor = ActorSDK.sharedActor().style.getConvStateDeliveredColor();
readColor = ActorSDK.sharedActor().style.getConvStateReadColor();
errorColor = ActorSDK.sharedActor().style.getConvStateErrorColor();
if (audioActor == null) {
audioActor = ActorSystem.system().actorOf(Props.create(new ActorCreator() {
@Override
public AudioPlayerActor create() {
return new AudioPlayerActor(context);
}
}), "actor/audio_player");
}
stateIcon = (TintImageView) itemView.findViewById(R.id.stateIcon);
time = (TextView) itemView.findViewById(R.id.time);
time.setTextColor(ActorSDK.sharedActor().style.getConvTimeColor());
duration = (TextView) itemView.findViewById(R.id.duration);
duration.setTextColor(ActorSDK.sharedActor().style.getConvTimeColor());
seekBar = (SeekBar) itemView.findViewById(R.id.audioSlide);
progressView = (CircularView) itemView.findViewById(R.id.progressView);
progressView.setColor(context.getResources().getColor(R.color.primary));
progressView.setMaxValue(100);
// seekBar.setOnTouchListener(new View.OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// return true;
// }
// });
// seekBar.setEnabled(false);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
float seek = (float) seekBar.getProgress() / (float) seekBar.getMax();
duration.setText(ActorSDK.sharedActor().getMessenger().getFormatter().formatDuration((int) (seek * currentDuration / 1000)));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
treckingTouch = true;
audioActor.send(new AudioPlayerActor.Stop());
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
float progress = (float) seekBar.getProgress() / (float) seekBar.getMax();
audioActor.send(new AudioPlayerActor.Seek(progress, currentAudio));
currentPlayingAudio = currentAudio;
}
});
mainContainer = (ViewGroup) itemView.findViewById(R.id.mainContainer);
messageBubble = (FrameLayout) itemView.findViewById(R.id.fl_bubble);
playBtn = (ImageView) itemView.findViewById(R.id.contact_avatar);
playBtn.getBackground().setColorFilter(Color.parseColor("#4295e3"), PorterDuff.Mode.MULTIPLY);
callback = new AudioPlayerActor.AudioPlayerCallback() {
@Override
public void onStart(final String fileName) {
mainThread.post(new Runnable() {
@Override
public void run() {
play(fileName);
}
});
}
@Override
public void onStop(final String fileName) {
mainThread.post(new Runnable() {
@Override
public void run() {
stop();
}
});
}
@Override
public void onPause(final String fileName, float progress) {
mainThread.post(new Runnable() {
@Override
public void run() {
if (currentAudio != null && currentAudio.equals(fileName)) {
pause();
}
}
});
}
@Override
public void onProgress(final String fileName, final float progress) {
mainThread.post(new Runnable() {
@Override
public void run() {
if (currentAudio != null && currentAudio.equals(fileName) && currentPlayingAudio.equals(currentAudio)) {
if (!treckingTouch) progress(progress);
}
}
});
}
@Override
public void onError(final String fileName) {
mainThread.post(new Runnable() {
@Override
public void run() {
if (currentAudio != null && currentAudio.equals(fileName)) {
Toast.makeText(context, "error playing this file", Toast.LENGTH_SHORT).show();
keepScreenOn(false);
}
}
});
}
};
audioActor.send(new AudioPlayerActor.RegisterCallback(callback));
onConfigureViewHolder();
}
private void play(String fileName) {
if (currentAudio != null && currentAudio.equals(fileName)) {
playBtn.setImageResource(R.drawable.ic_pause_white_24dp);
keepScreenOn(true);
} else {
stop();
}
}
private void progress(float progress) {
playBtn.setImageResource(R.drawable.ic_pause_white_24dp);
duration.setText(ActorSDK.sharedActor().getMessenger().getFormatter().formatDuration((int) (progress * currentDuration / 1000)));
seekBar.setProgress((int) (100 * progress));
}
private void stop() {
if (!treckingTouch) {
seekBar.setProgress(0);
playBtn.setImageResource(R.drawable.ic_play_arrow_white_24dp);
duration.setText(ActorSDK.sharedActor().getMessenger().getFormatter().formatDuration((int) (currentDuration / 1000)));
}
treckingTouch = false;
keepScreenOn(false);
}
private void pause() {
playBtn.setImageResource(R.drawable.ic_play_arrow_white_24dp);
keepScreenOn(false);
}
@Override
protected void bindData(final Message message, long readDate, long receiveDate, boolean isUpdated, PreprocessedData preprocessedData) {
VoiceContent audioMsg = (VoiceContent) message.getContent();
if (message.getSenderId() == myUid()) {
// messageBubble.getBackground().setColorFilter(messageBubble.getContext().getResources().getColor(R.color.conv_bubble), PorterDuff.Mode.MULTIPLY);
messageBubble.setBackgroundResource(R.drawable.conv_bubble_media_out);
} else {
messageBubble.setBackgroundResource(R.drawable.conv_bubble_media_in);
messageBubble.getBackground().setColorFilter(null);
}
// Update state
if (message.getSenderId() == myUid()) {
stateIcon.setVisibility(View.VISIBLE);
switch (message.getMessageState()) {
case ERROR:
stateIcon.setResource(R.drawable.msg_error);
stateIcon.setTint(errorColor);
break;
default:
case PENDING:
stateIcon.setResource(R.drawable.msg_clock);
stateIcon.setTint(waitColor);
break;
case SENT:
if (message.getSortDate() <= readDate) {
stateIcon.setResource(R.drawable.msg_check_2);
stateIcon.setTint(readColor);
} else if (message.getSortDate() <= receiveDate) {
stateIcon.setResource(R.drawable.msg_check_2);
stateIcon.setTint(deliveredColor);
} else {
stateIcon.setResource(R.drawable.msg_check_1);
stateIcon.setTint(sentColor);
}
break;
}
} else {
stateIcon.setVisibility(View.GONE);
}
// Update time
setTimeAndReactions(time);
currentDuration = ((VoiceContent) message.getContent()).getDuration();
duration.setText(ActorSDK.sharedActor().getMessenger().getFormatter().formatDuration((int) (currentDuration / 1000)));
// Update view
boolean needRebind = false;
if (isUpdated) {
// Resetting old content state
// Resetting binding
if (downloadFileVM != null) {
downloadFileVM.detach();
downloadFileVM = null;
}
if (uploadFileVM != null) {
uploadFileVM.detach();
uploadFileVM = null;
}
needRebind = true;
}
if (needRebind) {
// Resetting progress state
if (audioMsg.getSource() instanceof FileRemoteSource) {
boolean autoDownload = false;
if (audioMsg instanceof VoiceContent) {
autoDownload = messenger().isAudioAutoDownloadEnabled();
}
downloadFileVM = ActorSDK.sharedActor().getMessenger().bindFile(((FileRemoteSource) audioMsg.getSource()).getFileReference(),
autoDownload, new DownloadVMCallback(audioMsg));
} else if (audioMsg.getSource() instanceof FileLocalSource) {
uploadFileVM = ActorSDK.sharedActor().getMessenger().bindUpload(message.getRid(), new UploadVMCallback());
currentAudio = ((FileLocalSource) audioMsg.getSource()).getFileDescriptor();
stop();
bindPlayButton();
} else {
throw new RuntimeException("Unknown file source type: " + audioMsg.getSource());
}
}
}
private class DownloadVMCallback implements FileVMCallback {
private DocumentContent doc;
private DownloadVMCallback(DocumentContent doc) {
this.doc = doc;
}
@Override
public void onNotDownloaded() {
goneView(progressView);
playBtn.setImageResource(R.drawable.msg_audio_download_selector);
playBtn.setOnClickListener(null);
}
@Override
public void onDownloading(float progress) {
playBtn.setImageResource(R.drawable.msg_audio_download_selector);
progressView.setValue((int) (progress * 100));
showView(progressView);
playBtn.setOnClickListener(null);
}
@Override
public void onDownloaded(FileSystemReference reference) {
currentAudio = reference.getDescriptor();
goneView(progressView);
stop();
bindPlayButton();
}
}
private class UploadVMCallback implements UploadFileVMCallback {
@Override
public void onNotUploaded() {
goneView(progressView);
// playBtn.setImageResource(R.drawable.msg_audio_download_selector);
// playBtn.setOnClickListener(null);
stop();
bindPlayButton();
}
@Override
public void onUploading(float progress) {
progressView.setValue((int) (progress * 100));
showView(progressView);
}
@Override
public void onUploaded() {
goneView(progressView);
stop();
bindPlayButton();
}
}
private void bindPlayButton() {
playBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
audioActor.send(new AudioPlayerActor.Toggle(currentAudio));
currentPlayingAudio = currentAudio;
}
});
}
@Override
public void unbind() {
super.unbind();
// Unbinding model
if (downloadFileVM != null) {
downloadFileVM.detach();
downloadFileVM = null;
}
if (uploadFileVM != null) {
uploadFileVM.detach();
uploadFileVM = null;
}
audioActor.send(new AudioPlayerActor.RemoveCallback(callback));
messageBubble.getBackground().setColorFilter(null);
}
public static void stopPlaying() {
if (audioActor != null) {
audioActor.send(new AudioPlayerActor.Stop());
}
}
private void keepScreenOn(boolean on) {
if (context != null) {
Window window = ((FragmentActivity) context).getWindow();
if (on == true)
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
else
window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
}