<commit_before>package com.cube.storm.ui.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ProgressBar;

import com.cube.storm.UiSettings;
import com.cube.storm.ui.model.property.AnimationImageProperty;
import com.cube.storm.ui.model.property.ImageProperty;
import com.cube.storm.ui.model.property.SpotlightImageProperty;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;

import java.util.List;

/**
 * Augmented image view which uses the UniveralImageLoader library to display images and handles Storm animations.
 * <p/>
 *
 * @author <NAME>
 * @Project LightningUi
 */
public class ImageView extends android.widget.ImageView
{
	/**
	 * Listener alerted whenever the animation frame changes.
	 */
	public interface OnAnimationFrameChangeListener
	{
		void onAnimationFrameChange(ImageView imageView, int frameIndex, AnimationImageProperty frame);
	}

	/**
	 * Handler used to control animations. Null until an animation is explicitly
	 */
	private Handler animator = null;

	/**
	 * Runnable used to update the curent frame. Null until an animation is explicitly
	 */
	private Runnable displayNextFrame = null;

	public ImageView(Context context)
	{
		super(context);
	}

	public ImageView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
	}

	public ImageView(Context context, AttributeSet attrs, int defStyleAttr)
	{
		super(context, attrs, defStyleAttr);
	}

	public ImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
	{
		super(context, attrs, defStyleAttr, defStyleRes);
	}

	/**
	 * Alternately display each of a sequence of Storm animation frames.
	 *
	 * @param frames
	 * 		If null, the current image is cleared and all pending animation tasks are cancelled.
	 */
	public void populate(@Nullable final List<? extends AnimationImageProperty> frames)
	{
		populate(frames, null);
	}

	/**
	 * Alternately display each of a sequence of Storm animation frames, alerting an optional listener whenever the
	 * frame changes.
	 *
	 * @param frames
	 * 		If null, the current image is cleared and all pending animation tasks are cancelled.
	 * @param listener
	 */
	public void populate(@Nullable final List<? extends AnimationImageProperty> frames,
						 @Nullable final OnAnimationFrameChangeListener listener)
	{
		// Cancel all current loading tasks
		populate((ImageProperty)null);

		if (frames != null)
		{
			if (animator == null)
			{
				animator = new Handler();
			}

			displayNextFrame = new Runnable()
			{
				private int frameIndex = 0;

				@Override public void run()
				{
					AnimationImageProperty frame = frames.get(frameIndex % frames.size());
					populateFrame(frame, null);
					++frameIndex;
					animator.postDelayed(this, frame.getDelay());

					if (listener != null)
					{
						listener.onAnimationFrameChange(ImageView.this, frameIndex, frame);
					}
				}
			};
			animator.post(displayNextFrame);
		}
	}

	/**
	 * Alternately display each of a sequence of Storm spotlight frames, updating a text view to display the spotlight
	 * text whenever it changes.
	 *
	 * @param frames
	 * 		If null, the current image is cleared and all pending animation tasks are cancelled.
	 * @param textView
	 * 		{@link TextView#populate(com.cube.storm.ui.model.property.TextProperty, com.cube.storm.ui.model.property.LinkProperty)}
	 * 		will be called with the relevant details each time the spotlight changes.
	 */
	public void populate(@Nullable final List<? extends SpotlightImageProperty> frames, @NonNull TextView textView)
	{
		populate(frames, textView, null);
	}

	/**
	 * Alternately display each of a sequence of Storm spotlight frames, updating a text view and alerting an optional
	 * listener whenever the spotlight changes.
	 *
	 * @param frames
	 * 		If null, the current image is cleared and all pending animation tasks are cancelled.
	 * @param textView
	 * 		{@link TextView#populate(com.cube.storm.ui.model.property.TextProperty, com.cube.storm.ui.model.property.LinkProperty)}
	 * 		will be called with the relevant details each time the spotlight changes.
	 * @param listener
	 */
	public void populate(@Nullable final List<? extends SpotlightImageProperty> frames,
						 @NonNull final TextView textView,
						 @Nullable final OnAnimationFrameChangeListener listener)
	{
		populate(frames, new OnAnimationFrameChangeListener()
		{
			@Override public void onAnimationFrameChange(ImageView imageView,
														 int frameIndex,
														 AnimationImageProperty frame)
			{
				SpotlightImageProperty spotlightFrame = (SpotlightImageProperty)frame;
				textView.populate(spotlightFrame.getText(), spotlightFrame.getLink());

				if (listener != null)
				{
					listener.onAnimationFrameChange(imageView, frameIndex, frame);
				}
			}
		});
	}

	/**<commit_msg>Fix for when there is only one frame on an animated image view - stops the single image from flickering on the defined delay<commit_after>package com.cube.storm.ui.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ProgressBar;

import com.cube.storm.UiSettings;
import com.cube.storm.ui.model.property.AnimationImageProperty;
import com.cube.storm.ui.model.property.ImageProperty;
import com.cube.storm.ui.model.property.SpotlightImageProperty;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;

import java.util.List;

/**
 * Augmented image view which uses the UniveralImageLoader library to display images and handles Storm animations.
 * <p/>
 *
 * @author <NAME>
 * @Project LightningUi
 */
public class ImageView extends android.widget.ImageView
{
	/**
	 * Listener alerted whenever the animation frame changes.
	 */
	public interface OnAnimationFrameChangeListener
	{
		void onAnimationFrameChange(ImageView imageView, int frameIndex, AnimationImageProperty frame);
	}

	/**
	 * Handler used to control animations. Null until an animation is explicitly
	 */
	private Handler animator = null;

	/**
	 * Runnable used to update the curent frame. Null until an animation is explicitly
	 */
	private Runnable displayNextFrame = null;

	public ImageView(Context context)
	{
		super(context);
	}

	public ImageView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
	}

	public ImageView(Context context, AttributeSet attrs, int defStyleAttr)
	{
		super(context, attrs, defStyleAttr);
	}

	public ImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
	{
		super(context, attrs, defStyleAttr, defStyleRes);
	}

	/**
	 * Alternately display each of a sequence of Storm animation frames.
	 *
	 * @param frames
	 * 		If null, the current image is cleared and all pending animation tasks are cancelled.
	 */
	public void populate(@Nullable final List<? extends AnimationImageProperty> frames)
	{
		populate(frames, null);
	}

	/**
	 * Alternately display each of a sequence of Storm animation frames, alerting an optional listener whenever the
	 * frame changes.
	 *
	 * @param frames
	 * 		If null, the current image is cleared and all pending animation tasks are cancelled.
	 * @param listener
	 */
	public void populate(@Nullable final List<? extends AnimationImageProperty> frames,
						 @Nullable final OnAnimationFrameChangeListener listener)
	{
		// Cancel all current loading tasks
		populate((ImageProperty)null);

		if (frames != null)
		{
			if (animator == null)
			{
				animator = new Handler();
			}

			displayNextFrame = new Runnable()
			{
				private int frameIndex = 0;

				@Override public void run()
				{
					AnimationImageProperty frame = frames.get(frameIndex % frames.size());
					populateFrame(frame, null);
					++frameIndex;
					if (frames.size() > 1) animator.postDelayed(this, frame.getDelay());

					if (listener != null)
					{
						listener.onAnimationFrameChange(ImageView.this, frameIndex, frame);
					}
				}
			};
			animator.post(displayNextFrame);
		}
	}

	/**
	 * Alternately display each of a sequence of Storm spotlight frames, updating a text view to display the spotlight
	 * text whenever it changes.
	 *
	 * @param frames
	 * 		If null, the current image is cleared and all pending animation tasks are cancelled.
	 * @param textView
	 * 		{@link TextView#populate(com.cube.storm.ui.model.property.TextProperty, com.cube.storm.ui.model.property.LinkProperty)}
	 * 		will be called with the relevant details each time the spotlight changes.
	 */
	public void populate(@Nullable final List<? extends SpotlightImageProperty> frames, @NonNull TextView textView)
	{
		populate(frames, textView, null);
	}

	/**
	 * Alternately display each of a sequence of Storm spotlight frames, updating a text view and alerting an optional
	 * listener whenever the spotlight changes.
	 *
	 * @param frames
	 * 		If null, the current image is cleared and all pending animation tasks are cancelled.
	 * @param textView
	 * 		{@link TextView#populate(com.cube.storm.ui.model.property.TextProperty, com.cube.storm.ui.model.property.LinkProperty)}
	 * 		will be called with the relevant details each time the spotlight changes.
	 * @param listener
	 */
	public void populate(@Nullable final List<? extends SpotlightImageProperty> frames,
						 @NonNull final TextView textView,
						 @Nullable final OnAnimationFrameChangeListener listener)
	{
		populate(frames, new OnAnimationFrameChangeListener()
		{
			@Override public void onAnimationFrameChange(ImageView imageView, int frameIndex, AnimationImageProperty frame)
			{
				SpotlightImageProperty spotlightFrame = (SpotlightImageProperty)frame;
				textView.populate(spotlightFrame.getText(), spotlightFrame.getLink());

				if (listener != null)
				{
					listener.onAnimationFrameChange(imageView, frameIndex, frame);
				}
			}
		});
	}

	/**
{'fraction_non_alphanumeric': 0.08792599805258033, 'fraction_numerical': 0.001071080817916261, 'mean_word_length': 4.099801390268123, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3133446', 'n_tokens_mistral': 3215, 'n_tokens_neox': 2765, 'n_words': 889}