package com.sparseboolean.ifexplorer.ui;
import android.graphics.PorterDuff;
import android.content.Context;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import gem.kevin.util.FileUtil;
import gem.kevin.util.ui.NamedColor;
import gem.kevin.widget.DropAcceptable;
import gem.kevin.widget.OnDropDelegate;
import gem.kevin.widget.OpenDelegate;
import gem.kevin.widget.Openable;
public class DropableFilePathButton extends FilePathButton implements
DropAcceptable, Openable {
private static final String TAG = "gem-kevin_DropableFilePathButton";
public static final long HOVER_DECISION_COUNTDOWN = 1000L;
public static final int COLOR_DROP_AVAILABLE = 0x37000000 | NamedColor.RoyalBlue;
public static final int COLOR_DROP_NA_OPEN_AVAILABLE = 0x50000000 | NamedColor.LightCoral;
public static final int APLAH_TRANSPARENT = 0x00ffffff;
private OnDropDelegate mOnDropDelegate;
private OpenDelegate mOpenDelegate;
private CountDownTimer mHoverCountDownTimer; // Do a lazy initialization
public DropableFilePathButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DropableFilePathButton(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public DropableFilePathButton(Context context, String path,
FilePathButtonCallback callback) {
super(context, path, callback);
}
@Override
public boolean canAcceptDrop() {
if (mOnDropDelegate != null) {
return mOnDropDelegate.checkDropDataAcceptable(null, this);
}
return false;
}
@Override
public boolean canAppendContent() {
return FileUtil.isWritableDirectory(mFilePath);
}
@Override
public boolean canOpen() {
return FileUtil.isReadableDirectory(mFilePath);
}
@Override
public void markChildCanGetDragEvent(boolean childCanGetDragEvent) {
// this is a final DropAcceptable,
// no child to get drag events
}
@Override
public boolean onDragEnded(DragEvent event) {
boolean success = event.getResult();
if (mOnDropDelegate != null) {
if (!success) {
mOnDropDelegate.onDropFailed(this);
}
}
return false;
}
@Override
public boolean onDragEntered(DragEvent event) {
boolean canAcceptDrop = canAcceptDrop();
boolean canOpen = canOpen();
if (canAcceptDrop) {
mPathButton.getBackground().setColorFilter(COLOR_DROP_AVAILABLE,
PorterDuff.Mode.MULTIPLY);
} else {
if (canOpen) {
mPathButton.getBackground().setColorFilter(
COLOR_DROP_NA_OPEN_AVAILABLE, PorterDuff.Mode.MULTIPLY);
}
}
// If it can't open, then we do not call onDragHover on it.
// Bind behaviors 'open' and 'drag hover' to a single logic for performance purpose.
if (canOpen) {
if (mHoverCountDownTimer == null) {
mHoverCountDownTimer = new CountDownTimer(
HOVER_DECISION_COUNTDOWN, HOVER_DECISION_COUNTDOWN / 10) {
@Override
public void onFinish() {
onHover();
}
@Override
public void onTick(long millisUntilFinished) {
// Do nothing
Log.i(TAG, "Tick: " + millisUntilFinished);
}
};
}
mHoverCountDownTimer.start();
}
return canAcceptDrop;
}
@Override
public boolean onDragEvent(DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
Log.i(TAG, "DFPB Drag Started.");
return onDragStarted(event);
case DragEvent.ACTION_DRAG_ENTERED:
Log.i(TAG, "DFPB Drag entered.");
return onDragEntered(event);
case DragEvent.ACTION_DRAG_LOCATION:
return onDragMoveOn(event);
case DragEvent.ACTION_DRAG_EXITED:
Log.i(TAG, "DFPB Drag exited.");
return onDragExited(event);
case DragEvent.ACTION_DROP:
Log.i(TAG, "DFPB Drag droped.");
return onDrop(event);
case DragEvent.ACTION_DRAG_ENDED:
Log.i(TAG, "DFPB Drag ended.");
return onDragEnded(event);
}
return super.onDragEvent(event);
}
@Override
public boolean onDragExited(DragEvent event) {
mPathButton.getBackground().clearColorFilter();
if (mHoverCountDownTimer != null) {
mHoverCountDownTimer.cancel();
}
return true;
}
@Override
public boolean onDragMoveOn(DragEvent event) {
// Do nothing
return true;
}
@Override
public boolean onDragStarted(DragEvent event) {
return true;
}
@Override
public boolean onDrop(DragEvent event) {
mPathButton.getBackground().clearColorFilter();
if (mHoverCountDownTimer != null) {
mHoverCountDownTimer.cancel();
}
if (mOnDropDelegate != null) {
Object data = mOnDropDelegate.generateDropData();
boolean result = true;
if (mOnDropDelegate.checkDropDataAcceptable(data, this)) {
result = mOnDropDelegate.handleDrop(data, this);
if (result) {
mOnDropDelegate.onDropSuccess(this);
} else {
mOnDropDelegate.onDropFailed(this);
}
} else {
if (mOnDropDelegate.shouldDispathUnacceptableDropToParent(this)) {
result = super.onDragEvent(event);
} else {
// Only notify drop denial when the view has indicated it could possibly
// accept drop (Actual it could not)
// Task 'canOpen' as a possible drop indicator because it also changed the UI.
// User might tend to think it is dropable.
if (canOpen()) {
mOnDropDelegate.notifyDropDataDenied(data, this);
}
mOnDropDelegate.onDropFailed(this);
}
}
return result;
}
return true;
}
@Override
public void onHover() {
if (mOnDropDelegate != null) {
mOnDropDelegate.onHover(this);
}
}
@Override
public void open() {
Log.i(TAG, "open");
if (mOpenDelegate != null) {
mOpenDelegate.doOpen(this);
}
}
public void setOnDropDelegate(OnDropDelegate delegate) {
mOnDropDelegate = delegate;
}
public void setOpenDelegate(OpenDelegate delegate) {
mOpenDelegate = delegate;
}
}