<commit_before>package com.example.anvil.animpicker;

import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

import static trikita.anvil.DSL.*;

import trikita.anvil.Anvil;
import trikita.anvil.RenderableView;
import trikita.anvil.State;

// A simple picker component that looks like this:
//
//     <    foo    >
//
// When next button is pressed the item is moved to the right and
// the next item substitutes it like this:
//
//     < r   foo   >
//     < ar   foo  >
//     < bar   foo >
//     <  bar   fo >
//     <   bar   f >
//     <    bar    >
//
// Of course, if user clicks next button twice too fast - the animation
// should happen twice, or when the user presses next and previous buttons
// quickly - two animations should happen immidiately one after another.
//
// It may become too complicated when thinking of it in imperative style,
// but Anvil's declarative nature makes it really easy.
//
public class AnimatedPickerView extends RenderableView {

	public final static int ANIM_DURATION = 300; // 300ms for each animation

	//
	// State is a boolean variable which can be in either of two states and can
	// make a durable transition from one state to another
	//
	// This is handy to define animated events, like if we want next item animation
	// to happen we can set next state to true, then a few milliseconds later set
	// it back to false asking animation to stop.
	//
	// So, mNext state is on when the next item animation is happening,
	// mPrev state is on when the previous item animation is happening.
	// If both states are off - there is no animations and current item is
	// shown in the center.
	//
	enum Navigation {
		NONE,
		PREV,
		NEXT
	};
	private State mState = State.init(Navigation.NONE);

	private int mIndex = 0; // Current item index
	private String[] mItems = { "Mercury", "Venus", "Earth", "Mars", "Jupiter",
		"Saturn", "Uranus", "Neptune", "Pluto"};

	// View width between next and prev buttons
	// We can't tell it beforehand (it depends on the screen size and
	// orientation), buf for animations we need to use real
	// offsets in pixels. So we use config() binding to measure the real View
	// instance after it's inflated and remember its width here.
	private int mWidth = 0;

	public AnimatedPickerView(Context c) {
		super(c);
	}

	// When next button is clicked - slowly change mNext state to true, then
	// increase the item index, then set mNext back to false
	private View.OnClickListener mOnNextClicked = (v) -> {
		mState.set(Navigation.NEXT, ANIM_DURATION, () -> {
			mIndex = (mIndex + 1) % mItems.length;
		}).set(Navigation.NONE, 0);
	};

	// When next button is clicked - slowly change mPrev state to true, then
	// decrease the item index, then set mPrev back to false
	private View.OnClickListener mOnPrevClicked = (v) -> {
		mState.set(Navigation.PREV, ANIM_DURATION, () -> {
			mIndex = (mIndex + mItems.length - 1) % mItems.length;
		}).set(Navigation.NONE, 0);
	};

	public void view() {
		linearLayout(() -> {
			size(FILL, WRAP);
			orientation(LinearLayout.HORIZONTAL);

			button(() -> {
				text("<<<");
				onClick(mOnPrevClicked);
			});

			// Container for two items at most (one is disappearing, another one
			// replaces it). Centered item takes 50% of the width in the center,
			// so it's left offset is 25% as well as its right offset
			linearLayout(() -> {
				size(WRAP, FILL);
				weight(1);
				orientation(LinearLayout.HORIZONTAL);
				// here we measure container width after it's inflated (recurisvely
				// calling render() until the views have finished their layout
				if (mWidth <= 0) {
					mWidth = Anvil.currentView().getWidth();
					if (mWidth == 0) {
						Anvil.currentView().post(() -> Anvil.render());
					}
				}

				// Primary view, displays the current item
				frameLayout(() -> {
					// takes 50% of the container
					size(mWidth/2, FILL);
					// if it's replaced by the previous item - it's shifted full-width
					// to the left (from 25% to -25%) and fades out.
					anim(mState.is(Navigation.PREV),
						of("x", mWidth/4, -mWidth/4)
						.of("alpha", 1f, 0f)
						.duration(ANIM_DURATION));
					// if it's replaced by the next item - it's shifted full-width
					// to the right (from 25% to 75%) and fades out.
					anim(mState.is(Navigation.NEXT),
						of("x", mWidth/4, mWidth*3/4)
						.of("alpha", 1f, 0f)
						.duration(ANIM_DURATION));
					// if it's not animd at all - it's centered and is fully opaque
					// see below, custom method to render item content
					if (mState.is(Navigation.NONE)) {
						System.out.println("back to default values");
						x(mWidth/4);
						alpha(1f);
					}

					itemView(mIndex);
				});


				// Helper view - the "next" or the "previous" item
				// It is shown only during the animation phase
				frameLayout(() -> {
					size(mWidth/2, FILL);
					// previous item is moving from 75% to 25% of the container width
					anim(mState.is(Navigation.PREV),
						of("x", mWidth*3/4, mWidth/4)
						.of("alpha", 0f, 1f)
						.duration(ANIM_DURATION));
					// next item is moving from -25% to 25% of the container width
					anim(mState.is(Navigation.NEXT),
						of("x", -mWidth/4, mWidth/4)
						.of("alpha", 0f, 1f)
						.duration(ANIM_DURATION));
					// if no animation happens now - hide this helper view
					visibility(!mState.is(Navigation.NONE));
					// display the contents of the next or previous item in the list
					if (mState.is(Navigation.NEXT)) {
						itemView(mIndex + 1);
					} else {
						itemView(mIndex - 1);
					}
				});
			});

			button(() -> {
				text(">>>");
				onClick(mOnNextClicked);
			});
		});
	}

	//
	// Let's separate rendering of the individual item from the generic picker
	// component to make customizations easier
	//
	public void itemView(int index) {
		// Get text of the item in the list (using modulo, non-negative index)
		String item = mItems[(index + mItems.length) % mItems.length];

		textView(() -> {
			size(FILL, FILL);
			gravity(CENTER);<commit_msg>using property animations instead of anvil state<commit_after>package com.example.anvil.animpicker;

import android.content.Context;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.widget.LinearLayout;

import java.util.ArrayDeque;
import java.util.Deque;

import static trikita.anvil.DSL.*;

import trikita.anvil.Anvil;
import trikita.anvil.RenderableView;

// A simple picker component that looks like this:
//
//     <    foo    >
//
// When next button is pressed the item is moved to the right and
// the next item substitutes it like this:
//
//     < r   foo   >
//     < ar   foo  >
//     < bar   foo >
//     <  bar   fo >
//     <   bar   f >
//     <    bar    >
//
// Of course, if user clicks next button twice too fast - the animation
// should happen twice, or when the user presses next and previous buttons
// quickly - two animations should happen immidiately one after another.
//
public class AnimatedPickerView extends RenderableView {

	public final static int ANIM_DURATION = 3000; // 300ms for each animation

	public final static int ANIMS_PER_NAVIGATION = 2;

	enum Navigation { PREV, NEXT };

	private Deque<Navigation> mNavQueue = new ArrayDeque<>();
	private int mRunningAnims = 0;

	private int mIndex = 0; // Current item index
	private String[] mItems = { "Mercury", "Venus", "Earth", "Mars", "Jupiter",
		"Saturn", "Uranus", "Neptune", "Pluto"};

	// View width between next and prev buttons
	// We can't tell it beforehand (it depends on the screen size and
	// orientation), but for animations we need to use real
	// offsets in pixels.
	private int mWidth = 0;

	public AnimatedPickerView(Context c) {
		super(c);
	}

	public void view() {
		Navigation nav = mNavQueue.peek();
		linearLayout(() -> {
			size(FILL, WRAP);
			orientation(LinearLayout.HORIZONTAL);

			button(() -> {
				text("<<<");
				onClick(v -> {
					mNavQueue.offer(Navigation.PREV);
				});
			});

			// Container for two items at most (one is disappearing, another one
			// replaces it). Centered item takes 50% of the width in the center,
			// so it's left offset is 25% as well as its right offset
			linearLayout(() -> {
				size(WRAP, FILL);
				weight(1);
				orientation(LinearLayout.HORIZONTAL);

				// here we measure container width after it's inflated recurisvely
				// calling render() until the views have finished their layout
				if (mWidth <= 0) {
					if ((mWidth = Anvil.currentView().getWidth()) == 0) {
						post(Anvil::render);
					}
				}

				// Primary view, displays the current item
				frameLayout(() -> {
					// takes 50% of the container
					size(mWidth/2, FILL);

					if (nav == Navigation.PREV) {
						slide(mWidth/4, -mWidth/4, 1f, 0f);
					} else if (nav == Navigation.NEXT) {
						slide(mWidth/4, mWidth*3/4, 1f, 0f);
					} else {
						Anvil.currentView().setX(mWidth/4);
						Anvil.currentView().setAlpha(1f);
					}

					itemView(mIndex);
				});

				// Helper view - the "next" or the "previous" item
				// It is shown only during the animation phase
				frameLayout(() -> {
					size(mWidth/2, FILL);

					if (nav == Navigation.PREV) {
						visibility(true);
						slide(mWidth*3/4, mWidth/4, 0f, 1f);
						itemView(mIndex - 1);
					} else if (nav == Navigation.NEXT) {
						visibility(true);
						slide(-mWidth/4, mWidth/4, 0f, 1f);
						itemView(mIndex + 1);
					} else {
						visibility(false);
					}
				});
			});

			button(() -> {
				text(">>>");
				onClick(v -> {
					mNavQueue.offer(Navigation.NEXT);
				});
			});
		});
	}

	// Starts property animation for the current view
	// Uses ANIMS_PER_NAVIGATION limit to avoid starting new animations
	// on further render cycles
	private void slide(int from, int to, float fromAlpha, float toAlpha) {
		if (mRunningAnims == ANIMS_PER_NAVIGATION) {
			return;
		}
		mRunningAnims++;
		// Set inital values before animation and start animation
		Anvil.currentView().setX(from);
		Anvil.currentView().setAlpha(fromAlpha);
		Anvil.currentView().animate()
			.x(to)
			.alpha(toAlpha)
			.setDuration(ANIM_DURATION)
			.withEndAction(() -> {
				// When animation is finished - decrease the number of pending
				// animations and if coutned down to zero - pop current transition from
				// the stack
				mRunningAnims--;
				if (mRunningAnims == 0) {
					mIndex += (mNavQueue.poll() == Navigation.PREV ? -1 : +1);
					Anvil.render();
				}
			});
	}

	//
	// Let's separate rendering of the individual item from the generic picker
	// component to make customizations easier
	//
	public void itemView(int index) {
		// Get text of the item in the list (using modulo, non-negative index)
		String item = mItems[(index + mItems.length) % mItems.length];

		textView(() -> {
			size(FILL, FILL);
			gravity(CENTER);
{'fraction_non_alphanumeric': 0.12284226870033793, 'fraction_numerical': 0.00986391451274089, 'mean_word_length': 2.7784679089026914, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 47, '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': '3231254', 'n_tokens_mistral': 4134, 'n_tokens_neox': 3379, 'n_words': 1170}