content: 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);
  
          }
      }
  }
  