/*
* 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;
}
}
}