/*
* Copyright (C) 2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.saulmm.cui;
import android.databinding.BindingAdapter;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.constraint.ConstraintLayout;
import android.support.design.widget.BottomSheetDialogFragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.RelativeSizeSpan;
import android.transition.Scene;
import android.transition.Transition;
import android.transition.TransitionInflater;
import android.transition.TransitionManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.OvershootInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
import com.saulmm.cui.databinding.FragmentOrderFormBinding;
import com.saulmm.cui.databinding.LayoutFormOrderStep1Binding;
import com.saulmm.cui.databinding.LayoutFormOrderStep2Binding;
import com.saulmm.cui.databinding.LayoutOrderConfirmationBinding;
import com.saulmm.cui.model.Product;
import java.util.ArrayList;
import java.util.List;
import de.hdodenhof.circleimageview.CircleImageView;
public class OrderDialogFragment extends BottomSheetDialogFragment {
public static final String ID_SIZE_SUFFIX = "txt_size";
public static final String ID_COLOR_SUFFIX = "img_color";
public static final String ID_DATE_SUFFIX = "txt_date";
public static final String ID_TIME_SUFFIX = "txt_time";
private static final String ARG_PRODUCT = "arg_product";
private List<View> clonedViews = new ArrayList<>();
private FragmentOrderFormBinding binding;
private Transition selectedViewTransition;
private OrderSelection orderSelection;
public static class OrderSelection {
public int size = 0;
public int color = 0;
public String date = "";
public String time = "";
}
public interface Step1Listener {
void onSizeSelected(View v);
void onColorSelected(View v);
}
public interface Step2Listener {
void onDateSelected(View v);
void onTimeSelected(View v);
}
public static OrderDialogFragment newInstance(Product product) {
final Bundle args = new Bundle();
args.putSerializable(ARG_PRODUCT, product);
final OrderDialogFragment orderFragment = new OrderDialogFragment();
orderFragment.setArguments(args);
return orderFragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
binding = FragmentOrderFormBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
orderSelection = new OrderSelection();
selectedViewTransition = TransitionInflater.from(getContext())
.inflateTransition(R.transition.transition_selected_view);
binding.setProduct(getProduct());
binding.imgProduct.setImageDrawable(createProductImageDrawable(getProduct()));
binding.btnGo.setBackground(new ColorDrawable(ContextCompat.getColor(
getContext(), getProduct().color)));
initOrderStepOneView(binding.layoutStep1);
}
private void showDeliveryForm() {
binding.switcher.setDisplayedChild(1);
initOrderStepTwoView(binding.layoutStep2);
}
private void transitionSelectedView(View v) {
// Create the cloned view from the selected view at the same position
final View selectionView = createSelectionView(v);
// Add the cloned view to the parent constraint layout
if (clonedViews.size() < 2) {
binding.mainContainer.addView(selectionView);
clonedViews.add(selectionView);
}
// Perform the transition by changing constraint's layout params
startCloneAnimation(selectionView, getTargetView(v));
}
private void startCloneAnimation(View clonedView, View targetView) {
clonedView.post(() -> {
TransitionManager.beginDelayedTransition(
(ViewGroup) binding.getRoot(), selectedViewTransition);
// Fires the transition
clonedView.setLayoutParams(SelectedParamsFactory
.endParams(clonedView, targetView));
});
}
private View createSelectionView(View v) {
final String resourceName = getResources().getResourceEntryName(v.getId());
return (resourceName.startsWith(ID_COLOR_SUFFIX))
? createSelectedColorView((ImageView) v)
: createSelectedTextView(v);
}
private View getTargetView(View v) {
final String resourceName = getResources().getResourceEntryName(v.getId());
if (resourceName.startsWith(ID_SIZE_SUFFIX) ||
resourceName.startsWith(ID_DATE_SUFFIX)) {
v.setId(R.id.first_position);
return binding.txtLabelSize;
} else if (resourceName.startsWith(ID_COLOR_SUFFIX) ||
resourceName.startsWith(ID_TIME_SUFFIX)) {
v.setId(R.id.second_position);
return binding.txtLabelColour;
}
throw new IllegalStateException();
}
@BindingAdapter("app:spanOffset")
public static void setItemSpan(View v, int spanOffset) {
final String itemText = ((TextView) v).getText().toString();
final SpannableString sString = new SpannableString(itemText);
sString.setSpan(new RelativeSizeSpan(1.65f), itemText.length() - spanOffset, itemText.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
((TextView) v).setText(sString);
}
private void initOrderStepOneView(LayoutFormOrderStep1Binding layoutStep1) {
binding.btnGo.setOnClickListener(v -> {
binding.txtAction.setText(R.string.action_book);
for (View clonedView : clonedViews)
binding.mainContainer.removeView(clonedView);
clonedViews.clear();
showDeliveryForm();
});
layoutStep1.setListener(new Step1Listener() {
@Override
public void onSizeSelected(View v) {
if (orderSelection.size == 0) {
orderSelection.size = Integer.parseInt(((TextView) v).getText().toString());
v.setSelected(true);
transitionSelectedView(v);
}
}
@Override
public void onColorSelected(View v) {
if (orderSelection.color == 0) {
orderSelection.color = ((ColorDrawable) ((ImageView) v).getDrawable()).getColor();
v.setSelected(true);
transitionSelectedView(v);
}
}
});
}
private void initOrderStepTwoView(LayoutFormOrderStep2Binding step2Binding) {
binding.btnGo.setOnClickListener(v -> changeToConfirmScene());
step2Binding.setListener(new Step2Listener() {
@Override
public void onDateSelected(View v) {
if (orderSelection.date.isEmpty()) {
orderSelection.date = getCleanedText(v);
v.setSelected(true);
transitionSelectedView(v);
}
}
@Override
public void onTimeSelected(View v) {
if (orderSelection.time.isEmpty()) {
orderSelection.time = getCleanedText(v);
v.setSelected(true);
transitionSelectedView(v);
}
}
});
}
private String getCleanedText(View v) {
return ((TextView) v).getText().toString().replace("\n", " ");
}
private View createSelectedTextView(View v) {
final TextView fakeSelectedTextView = new TextView(
getContext(), null, R.attr.selectedTextStyle);
final String resourceName = getResources().getResourceEntryName(v.getId());
if (resourceName.startsWith(ID_DATE_SUFFIX))
fakeSelectedTextView.setText(orderSelection.date);
else if (resourceName.startsWith(ID_TIME_SUFFIX))
fakeSelectedTextView.setText(orderSelection.time);
else if (resourceName.startsWith(ID_SIZE_SUFFIX))
fakeSelectedTextView.setText(String.valueOf(orderSelection.size));
fakeSelectedTextView.setLayoutParams(SelectedParamsFactory.startTextParams(v));
return fakeSelectedTextView;
}
private View createSelectedColorView(ImageView selectedView) {
final ImageView fakeImageView = new CircleImageView(
getContext(), null, R.attr.colorStyle);
fakeImageView.setImageDrawable(selectedView.getDrawable());
fakeImageView.setLayoutParams(SelectedParamsFactory.startColorParams(selectedView));
return fakeImageView;
}
private void changeToConfirmScene() {
final LayoutOrderConfirmationBinding confBinding = prepareConfirmationBinding();
final Scene scene = new Scene(binding.content,
((ViewGroup) confBinding.getRoot()));
scene.setEnterAction(onEnterConfirmScene(confBinding));
final Transition transition = TransitionInflater.from(getContext())
.inflateTransition(R.transition.transition_confirmation_view);
TransitionManager.go(scene, transition);
}
private LayoutOrderConfirmationBinding prepareConfirmationBinding() {
LayoutOrderConfirmationBinding confBinding = LayoutOrderConfirmationBinding
.inflate(LayoutInflater.from(getContext()), binding.mainContainer, false);
confBinding.getRoot().setBackground(new ColorDrawable(ContextCompat.getColor(
getContext(), getProduct().color)));
confBinding.setProduct(getProduct());
confBinding.setSelection(orderSelection);
confBinding.imgProduct.setImageDrawable(ContextCompat
.getDrawable(getContext(), getProduct().image));
confBinding.txtColor.setText(getString(R.string.txt_label_conf_color, String.format(
"#%06X", (0xFFFFFF & getProduct().color))));
return confBinding;
}
private Product getProduct() {
return (Product) getArguments().getSerializable(ARG_PRODUCT);
}
private Drawable createProductImageDrawable(Product product) {
final ShapeDrawable background = new ShapeDrawable();
background.setShape(new OvalShape());
background.getPaint().setColor(ContextCompat.getColor(getContext(), product.color));
final BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(),
BitmapFactory.decodeResource(getResources(), product.image));
final LayerDrawable layerDrawable = new LayerDrawable
(new Drawable[]{background, bitmapDrawable});
final int padding = (int) getResources().getDimension(R.dimen.spacing_huge);
layerDrawable.setLayerInset(1, padding, padding, padding, padding);
return layerDrawable;
}
@NonNull
private Runnable onEnterConfirmScene(LayoutOrderConfirmationBinding confirmationBinding) {
return () -> {
ViewCompat.animate(confirmationBinding.txtSubtitle)
.scaleX(1).scaleY(1)
.setInterpolator(new OvershootInterpolator())
.setStartDelay(200)
.start();
};
}
private static class SelectedParamsFactory {
private static ConstraintLayout.LayoutParams startColorParams(View selectedView) {
final int colorSize = selectedView.getContext().getResources()
.getDimensionPixelOffset(R.dimen.product_color_size);
final ConstraintLayout.LayoutParams layoutParams =
new ConstraintLayout.LayoutParams(colorSize, colorSize);
setStartState(selectedView, layoutParams);
return layoutParams;
}
private static ConstraintLayout.LayoutParams startTextParams(View selectedView) {
final ConstraintLayout.LayoutParams layoutParams =
new ConstraintLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
setStartState(selectedView, layoutParams);
return layoutParams;
}
private static void setStartState(View selectedView, ConstraintLayout.LayoutParams layoutParams) {
layoutParams.topToTop = ((ViewGroup) selectedView.getParent().getParent()).getId();
layoutParams.leftToLeft = ((ViewGroup) selectedView.getParent().getParent()).getId();
layoutParams.setMargins((int) selectedView.getX(), (int) selectedView.getY(), 0, 0);
}
private static ConstraintLayout.LayoutParams endParams(View v, View targetView) {
final ConstraintLayout.LayoutParams layoutParams =
(ConstraintLayout.LayoutParams) v.getLayoutParams();
final int marginLeft = v.getContext().getResources()
.getDimensionPixelOffset(R.dimen.spacing_medium);
layoutParams.setMargins(marginLeft, 0, 0, 0);
layoutParams.topToTop = targetView.getId();
layoutParams.startToEnd = targetView.getId();
layoutParams.bottomToBottom = targetView.getId();
return layoutParams;
}
}
}