package com.androidexperiments.landmarker.widget;
import android.content.Context;
import android.graphics.Point;
import android.location.Location;
import android.os.Handler;
import android.support.v4.view.GestureDetectorCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import com.google.creativelabs.androidexperiments.typecompass.R;
import com.androidexperiments.landmarker.data.NearbyPlace;
import java.util.ArrayList;
import java.util.List;
import butterknife.ButterKnife;
import butterknife.InjectView;
import de.greenrobot.event.EventBus;
import se.walkercrou.places.Place;
/**
* Handles 4 textviews and displays them in NSEW orientation
*/
public class DirectionalTextViewContainer extends FrameLayout
{
private static final String TAG = DirectionalTextViewContainer.class.getSimpleName();
//defaults
private int MIN_Y_MOVEMENT = -20;
private int MAX_Y_MOVEMENT = -1000;
private int TOTAL_Y_MOVEMENT = -980;
@InjectView(R.id.dtv_north) DirectionalTextView mNorth;
@InjectView(R.id.dtv_east) DirectionalTextView mEast;
@InjectView(R.id.dtv_south) DirectionalTextView mSouth;
@InjectView(R.id.dtv_west) DirectionalTextView mWest;
ArrayList<NearbyPlace> mNorthernPlaces, mEasternPlaces, mSouthernPlaces, mWesternPlaces;
private Handler mDrawingHandler = new Handler();
private boolean mIsDrawing = true;
private int mViewWidth = 0;
// private double mCurrentDegrees = 0;
public DirectionalTextViewContainer(Context context) {
super(context);
}
public DirectionalTextViewContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DirectionalTextViewContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
ButterKnife.inject(this, this);
mNorth.setDir("N");
mEast.setDir("E");
mWest.setDir("W");
mSouth.setDir("S");
setupMovementConstants();
setupTouchListener();
}
private void setupMovementConstants()
{
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Point windowSize = new Point();
wm.getDefaultDisplay().getSize(windowSize);
MAX_Y_MOVEMENT = -windowSize.y / 2;
TOTAL_Y_MOVEMENT = MAX_Y_MOVEMENT - MIN_Y_MOVEMENT;
}
private void setupTouchListener()
{
final GestureDetectorCompat gd = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onSingleTapConfirmed(MotionEvent e)
{
Log.d(TAG, "singleTap: " + getTappedView(e));
EventBus.getDefault().post(new OnPlaceClickedEvent(getTappedView(e).getCurrentPlace()));
return false;
}
});
this.setOnTouchListener(new OnTouchListener()
{
float mStartY = 0.f;
DirectionalTextView view = null;
@Override
public boolean onTouch(View v, MotionEvent event)
{
gd.onTouchEvent(event);
int type = event.getActionMasked();
float dif, percent;
switch(type)
{
case MotionEvent.ACTION_DOWN:
view = getTappedView(event);
Log.d(TAG, "onTouchDown: " + view.getDir());
mStartY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
dif = mStartY - event.getRawY();
if(dif < MIN_Y_MOVEMENT && dif > MAX_Y_MOVEMENT)
{
percent = dif / TOTAL_Y_MOVEMENT;
if(view != null) {
view.updatePostition(percent);
}
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if(view!= null)
{
dif = mStartY - event.getRawY();
percent = dif / TOTAL_Y_MOVEMENT;
if(percent > .5f)
view.springUp();
else
view.returnToPosition();
view = null;
}
break;
}
return true;
}
});
}
private DirectionalTextView getTappedView(MotionEvent e)
{
float tapX = e.getX();
float nx = mNorth.getX(), ex = mEast.getX(),
sx = mSouth.getX(), wx = mWest.getX();
//the weird one - since south will move to complete opposite side of screen
//depending on whether its to the right or left.
if((tapX >= ex && tapX < sx) || (tapX >= ex && sx < mViewWidth * -2))
return mEast;
//everything else is pretty straight forward
else if(tapX >= nx && tapX < ex)
return mNorth;
else if(tapX >= wx && tapX < nx)
return mWest;
//south is most finicky but if we test for all above cases, only remaining woudld be south
else
return mSouth;
}
public void updatePlaces(List<Place> places, Location lastLocation)
{
//wipe old places
mNorthernPlaces = new ArrayList<>();
mEasternPlaces = new ArrayList<>();
mSouthernPlaces = new ArrayList<>();
mWesternPlaces = new ArrayList<>();
for(Place place : places)
{
Location placeLoc = new Location("placeLoc");
placeLoc.setLatitude(place.getLatitude());
placeLoc.setLongitude(place.getLongitude());
// Log.d(TAG, "degrees to " + place.getName() + ": " + lastLocation.bearingTo(placeLoc) + " distance: " + lastLocation.distanceTo(placeLoc));
float bearing = lastLocation.bearingTo(placeLoc);
float distance = lastLocation.distanceTo(placeLoc);
NearbyPlace newPlace = new NearbyPlace(distance, place.getName());
//simple but useful
if(bearing > -45.f && bearing < 45.f) // north
mNorthernPlaces.add(newPlace);
else if(bearing > 45.f && bearing < 135.f) // east
mEasternPlaces.add(newPlace);
else if(bearing < -45.f && bearing > -135.f) // west
mWesternPlaces.add(newPlace);
else
mSouthernPlaces.add(newPlace);
}
mNorth.setPlaces(mNorthernPlaces);
mEast.setPlaces(mEasternPlaces);
mWest.setPlaces(mWesternPlaces);
mSouth.setPlaces(mSouthernPlaces);
}
public void updateFakePlaces()
{
mNorth.setText("Empire State Building");
mEast.setText("Williamsburg Bridge");
mSouth.setText("One World Trade");
mWest.setText("Chelsea Piers");
}
/**
* degrees range from -180 -> 180, 0 being due EAST and -90 being north
* @param degrees
*/
public void updateView(double degrees)
{
//hack
degrees = (degrees + 180) % 360 - 90;
if(degrees < 0)
degrees = 360 + degrees;
if(mViewWidth == 0)
mViewWidth = mEast.getWidth();
// mCurrentDegrees = degrees;
//180 north 0 south 270 east 90 west
float DEGREE = 90.f;
float northOffset = ((float) degrees - 180.f) / DEGREE;
float westOffset = ((float) degrees - 270) / DEGREE;
float eastOffset = ((float) degrees - 90) / DEGREE;
//south is weird
float southOffset = 0.f;
if(degrees > 0.f && degrees < 90.f)
southOffset = ((float)degrees) / DEGREE;
else
southOffset = ((float)degrees - 360) / DEGREE;
mNorth.setTranslation(northOffset, mViewWidth);
mWest.setTranslation(westOffset, mViewWidth);
mEast.setTranslation(eastOffset, mViewWidth);
mSouth.setTranslation(southOffset, mViewWidth);
}
public void animateIn()
{
if(this.getVisibility() == GONE)
{
Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.show_directional_text_views);
this.startAnimation(anim);
this.setVisibility(VISIBLE);
}
}
public void startDrawing()
{
mIsDrawing = true;
mDrawingHandler.post(new Runnable() {
@Override
public void run() {
if(!mIsDrawing) return;
mNorth.drawView();
mWest.drawView();
mEast.drawView();
mSouth.drawView();
mDrawingHandler.postDelayed(this, 16);
}
});
}
public void stopDrawing() {
mIsDrawing = false;
}
public static class OnPlaceClickedEvent{
public NearbyPlace place;
public OnPlaceClickedEvent(NearbyPlace place) {
this.place = place;
}
}
}