/* * Copyright (C) 2012 The CyanogenMod Project * * 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.cyanogenmod.filemanager.ui.widgets; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Animation; import android.view.animation.Transformation; import android.widget.LinearLayout; import android.widget.TextView; import com.cyanogenmod.filemanager.R; import com.cyanogenmod.filemanager.model.FileSystemObject; import com.cyanogenmod.filemanager.util.FileHelper; import java.util.List; /** * A view that holds the selection of files */ public class SelectionView extends LinearLayout { /** * @hide */ int mViewHeight; private TextView mStatus; private int mEffectDuration; /** * Constructor of <code>SelectionView</code>. * * @param context The current context * @param attrs The attributes of the XML tag that is inflating the view. */ public SelectionView(Context context, AttributeSet attrs) { super(context, attrs); init(); } /** * Constructor of <code>SelectionView</code>. * * @param context The current context * @param attrs The attributes of the XML tag that is inflating the view. * @param defStyle The default style to apply to this view. If 0, no style * will be applied (beyond what is included in the theme). This may * either be an attribute resource, whose value will be retrieved * from the current theme, or an explicit style resource. */ public SelectionView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } /** * Method that initializes the view. This method loads all the necessary * information and create an appropriate layout for the view */ private void init() { //Add the view of the breadcrumb View content = inflate(getContext(), R.layout.navigation_view_selectionbar, null); content.setLayoutParams(new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); // Obtain the height of the view for use in expand/collapse animation getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { SelectionView.this.mViewHeight = getHeight(); getViewTreeObserver().removeOnGlobalLayoutListener(this); setVisibility(View.GONE); LayoutParams params = (LayoutParams)SelectionView.this.getLayoutParams(); params.height = 0; } }); //Recovery all views this.mStatus = (TextView)content.findViewById(R.id.navigation_status_selection_label); // Obtain the duration of the effect this.mEffectDuration = getContext().getResources().getInteger(android.R.integer.config_shortAnimTime); addView(content); } /** * Method that computes the selection and returns a text message. * * @param selection The selection * @return String The computed text from the selection */ private String computeSelection(List<FileSystemObject> selection) { int folders = 0; int files = 0; int cc = selection.size(); for (int i = 0; i < cc; i++) { FileSystemObject fso = selection.get(i); if (FileHelper.isDirectory(fso)) { folders++; } else { files++; } } // Get the string if (folders == 1 && files == 0) { return getContext().getString(R.string.selection_one_folder, Integer.valueOf(folders)); } if (folders > 1 && files == 0) { return getContext().getString( R.string.selection_other_folders, Integer.valueOf(folders)); } if (folders == 0 && files == 1) { return getContext().getString(R.string.selection_one_file, Integer.valueOf(files)); } if (folders == 0 && files >= 1) { return getContext().getString( R.string.selection_other_files, Integer.valueOf(files)); } if (folders > 1 && files == 1) { return getContext().getString( R.string.selection_other_folders_one_file, Integer.valueOf(folders), Integer.valueOf(files)); } if (folders == 1 && files >= 1) { return getContext().getString( R.string.selection_one_folder_other_files, Integer.valueOf(folders), Integer.valueOf(files)); } return getContext().getString( R.string.selection_other_folders_other_files, Integer.valueOf(folders), Integer.valueOf(files)); } /** * Method that sets the {@link FileSystemObject} selection list * * @param newSelection The new selection list */ public void setSelection(List<FileSystemObject> newSelection) { // Compute the selection if (newSelection != null && newSelection.size() > 0) { this.mStatus.setText(computeSelection(newSelection)); } // Requires show the animation (expand or collapse)? // Is the current state need to be changed? if ((newSelection == null || newSelection.size() == 0) && this.getVisibility() == View.GONE) { return; } if ((newSelection != null && newSelection.size() > 0) && this.getVisibility() == View.VISIBLE) { return; } // Need some animation final ExpandCollapseAnimation.ANIMATION_TYPE effect = (newSelection != null && newSelection.size() > 0) ? ExpandCollapseAnimation.ANIMATION_TYPE.EXPAND : ExpandCollapseAnimation.ANIMATION_TYPE.COLLAPSE; ExpandCollapseAnimation animation = new ExpandCollapseAnimation( this, this.mViewHeight, this.mEffectDuration, effect); animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation anim) { LayoutParams params = (LayoutParams)getLayoutParams(); if (effect.compareTo(ExpandCollapseAnimation.ANIMATION_TYPE.EXPAND) == 0) { params.height = 0; } else if (effect.compareTo(ExpandCollapseAnimation.ANIMATION_TYPE.COLLAPSE) == 0) { params.height = SelectionView.this.mViewHeight; } SelectionView.this.setVisibility(View.VISIBLE); } @Override public void onAnimationRepeat(Animation anim) {/**NON BLOCK**/} @Override public void onAnimationEnd(Animation anim) { LayoutParams params = (LayoutParams)getLayoutParams(); if (effect.compareTo(ExpandCollapseAnimation.ANIMATION_TYPE.COLLAPSE) == 0) { params.height = 0; requestLayout(); SelectionView.this.setVisibility(View.GONE); } else { params.height = SelectionView.this.mViewHeight; requestLayout(); SelectionView.this.setVisibility(View.VISIBLE); } } }); animation.setInterpolator(new AccelerateDecelerateInterpolator()); startAnimation(animation); } /** * An animation effect for expand or collapse the view * */ private static class ExpandCollapseAnimation extends Animation { /** * The enumeration of the types of animation effects */ public enum ANIMATION_TYPE { EXPAND, COLLAPSE } private final View mView; private final LayoutParams mViewLayoutParams; private final int mViewHeight; private final ANIMATION_TYPE mEffect; /** * Constructor of <code>ExpandCollapseAnimation</code> * * @param view The view to animate * @param viewHeight The maximum height of view. Used to compute the animation translation * @param duration The duration of the animation * @param effect The effect of the animation */ public ExpandCollapseAnimation( View view, int viewHeight, int duration, ANIMATION_TYPE effect) { super(); this.mView = view; this.mViewHeight = viewHeight; this.mEffect = effect; this.mViewLayoutParams = (LayoutParams) view.getLayoutParams(); setDuration(duration); } /** * {@inheritDoc} */ @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); if (interpolatedTime < 1.0f) { int height = (int)(this.mViewHeight * interpolatedTime); if (this.mEffect.compareTo(ANIMATION_TYPE.EXPAND) == 0) { this.mViewLayoutParams.height = height; } else { this.mViewLayoutParams.height = this.mViewHeight - height; } this.mView.setLayoutParams(this.mViewLayoutParams); this.mView.requestLayout(); } } /** * {@inheritDoc} */ @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); } /** * {@inheritDoc} */ @Override public boolean willChangeBounds() { return true; } } }