Skip to content

Commit

Permalink
Add blank space at edges, and a bit of 3D.
Browse files Browse the repository at this point in the history
The left/right edges of the screen may be difficult for users to reach,
so this change makes the EqualizerView a bit narrower.  The first and
last bars now have a double-wide touch target.

Use the extra space for a simple orthograpic projection.
  • Loading branch information
pmarks-net committed Jan 28, 2018
1 parent 2f1f9ef commit e058883
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 32 deletions.
6 changes: 3 additions & 3 deletions app/build.gradle
Expand Up @@ -2,7 +2,7 @@ apply plugin: 'com.android.application'

android {
compileSdkVersion 23
buildToolsVersion '23.0.2'
buildToolsVersion '23.0.3'

defaultConfig {
applicationId 'net.pmarks.chromadoze'
Expand All @@ -19,6 +19,6 @@ android {
}

dependencies {
compile 'com.android.support:support-v4:23.1.1'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:appcompat-v7:23.4.0'
}
4 changes: 2 additions & 2 deletions app/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.pmarks.chromadoze"
android:versionCode="22"
android:versionName="3.5.5">
android:versionCode="23"
android:versionName="3.6-git">

<uses-permission android:name="android.permission.WAKE_LOCK" />

Expand Down
129 changes: 106 additions & 23 deletions app/src/main/java/net/pmarks/chromadoze/EqualizerView.java
Expand Up @@ -23,16 +23,26 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class EqualizerView extends android.view.View implements UIState.LockListener {
private static final int BAND_COUNT = SpectrumData.BAND_COUNT;

private final Paint mBarColor[] = new Paint[BAND_COUNT];
private final Paint mBaseColor[] = new Paint[4];
private final Paint mWhite = new Paint();
// 3D projection offsets (multiple of mBarWidth)
private static final float PROJECT_X = 0.4f;
private static final float PROJECT_Y = -0.25f;

// L=light, M=medium, D=dark
private final Paint mBarColorL[] = new Paint[BAND_COUNT];
private final Paint mBarColorM[] = new Paint[BAND_COUNT];
private final Paint mBarColorD[] = new Paint[BAND_COUNT];
private final Paint mBaseColorL[] = new Paint[4];
private final Paint mBaseColorM[] = new Paint[4];
private final Paint mBaseColorD[] = new Paint[4];

private UIState mUiState;

Expand All @@ -41,8 +51,16 @@ public class EqualizerView extends android.view.View implements UIState.LockList
private float mBarWidth;
private float mZeroLineY;

private Path mCubeTop;
private Path mCubeSide;

public EqualizerView(Context context, AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// On the Nexus S, hardware acceleration breaks Path.offset(),
// and it seems unnecessary for our tiny polygons.
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
makeColors();
}

Expand All @@ -57,40 +75,77 @@ private void makeColors() {
Paint p = new Paint();
int x = (bmp.getWidth() - 1) * i / (BAND_COUNT - 1);
p.setColor(bmp.getPixel(x, 0));
mBarColor[i] = p;
mBarColorL[i] = p;
}
darken(0.7f, mBarColorL, mBarColorM);
darken(0.5f, mBarColorL, mBarColorD);

int i = 0;
for (int v : new int[]{100, 75, 55, 50}) {
Paint p = new Paint();
p.setColor(Color.rgb(v, v, v));
mBaseColor[i++] = p;
mBaseColorL[i++] = p;
}
darken(0.7f, mBaseColorL, mBaseColorM);
darken(0.5f, mBaseColorL, mBaseColorD);
}

mWhite.setColor(Color.WHITE);
private void darken(float mult, Paint[] src, Paint[] dst) {
if (src.length != dst.length) {
throw new IllegalArgumentException("length mismatch");
}
for (int i = 0; i < src.length; i++) {
int color = src[i].getColor();
int r = (int) (Color.red(color) * mult);
int g = (int) (Color.green(color) * mult);
int b = (int) (Color.blue(color) * mult);
Paint p = new Paint(src[i]);
p.setColor(Color.argb(Color.alpha(color), r, g, b));
dst[i] = p;
}
}

@Override
protected void onDraw(Canvas canvas) {
final Phonon ph = mUiState != null ? mUiState.getPhonon() : null;
final boolean isLocked = mUiState != null ? mUiState.getLocked() : false;
final Path p = new Path();

for (int i = 0; i < BAND_COUNT; i++) {
float bar = ph != null ? ph.getBar(i) : .5f;
float startX = mBarWidth * i;
float startX = bandToX(i);
float stopX = startX + mBarWidth;
float startY = barToY(bar);
float midY = startY + mBarWidth;

// Lower the brightness and contrast when locked.
int baseCol = i % 2 + (isLocked ? 2 : 0);

// Bar right (the top-left corner of this rectangle will be clipped.)
float projX = mBarWidth * PROJECT_X;
float projY = mBarWidth * PROJECT_Y;
canvas.drawRect(stopX, midY + projY,stopX + projX, mHeight, mBaseColorD[baseCol]);

// Bar front
canvas.drawRect(startX, midY, stopX, mHeight, mBaseColorL[baseCol]);

if (bar > 0) {
canvas.drawRect(startX, startY, stopX, midY, mBarColor[i]);
}
// Cube right
mCubeSide.offset(stopX, startY, p);
canvas.drawPath(p, mBarColorD[i]);

// Lower the brightness and contrast when locked.
canvas.drawRect(startX, midY, stopX, mHeight,
mBaseColor[i % 2 + (isLocked ? 2 : 0)]);
}
// Cube top
mCubeTop.offset(startX, startY, p);
canvas.drawPath(p, mBarColorM[i]);

canvas.drawLine(0, mZeroLineY, mWidth, mZeroLineY, mWhite);
// Cube front
canvas.drawRect(startX, startY, stopX, midY, mBarColorL[i]);
} else {
// Bar top
mCubeTop.offset(startX, midY, p);
canvas.drawPath(p, mBaseColorM[baseCol]);
}
}
}

private float mLastX;
Expand Down Expand Up @@ -140,8 +195,30 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = getWidth();
mHeight = getHeight();
mBarWidth = mWidth / BAND_COUNT;
mBarWidth = mWidth / (BAND_COUNT + 2);
mZeroLineY = mHeight * .9f;
mCubeTop = projectCube(mBarWidth, true);
mCubeSide = projectCube(mBarWidth, false);
}

// Draw the top or right side of a cube.
private static Path projectCube(float unit, boolean isTop) {
float projX = unit * PROJECT_X;
float projY = unit * PROJECT_Y;
Path p = new Path();
p.moveTo(0, 0);
p.lineTo(projX, projY);
if (isTop) {
// Top
p.lineTo(unit + projX, projY);
p.lineTo(unit, 0);
} else {
// Side
p.lineTo(projX, unit + projY);
p.lineTo(0, unit);
}
p.close();
return p;
}

private float yToBar(float y) {
Expand All @@ -159,15 +236,24 @@ private float barToY(float barHeight) {
return (1f - barHeight) * (mZeroLineY - mBarWidth);
}

private int getBarIndex(float x) {
int out = (int) (x / mBarWidth);
// Accepts 0 <= barIndex < BAND_COUNT,
// leaving a 1-bar gap on each side of the screen.
private float bandToX(int barIndex) {
return mBarWidth * (barIndex + 1);
}

// Returns 0 <= out < BAND_COUNT,
// leaving a 1-bar gap on each side of the screen.
private int xToBand(float x) {
int out = ((int) (x / mBarWidth)) - 1;
if (out < 0) {
out = 0;
}
if (out > BAND_COUNT - 1) {
out = BAND_COUNT - 1;
}
return out;

}

// Starting bar?
Expand All @@ -188,15 +274,12 @@ private void touchLine(PhononMutable phm, float stopX, float stopY) {
float startY = mLastY;
mLastX = stopX;
mLastY = stopY;
int startBand = getBarIndex(startX);
int stopBand = getBarIndex(stopX);
int startBand = xToBand(startX);
int stopBand = xToBand(stopX);
int direction = stopBand > startBand ? 1 : -1;
for (int i = startBand; i != stopBand; i += direction) {
// Get the x-coordinate where we exited band i.
float exitX = i * mBarWidth;
if (direction > 0) {
exitX += mBarWidth;
}
float exitX = bandToX(direction < 0 ? i : i + 1);

// Get the Y value at exitX.
float slope = (stopY - startY) / (stopX - startX);
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/layout/about_fragment.xml
Expand Up @@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingBottom="10sp"
android:text="© 2016 Paul Marks" />
android:text="© 2018 Paul Marks" />

<TextView
android:layout_width="wrap_content"
Expand Down
4 changes: 3 additions & 1 deletion build.gradle
Expand Up @@ -2,14 +2,16 @@
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.android.tools.build:gradle:3.0.1'
}
}

allprojects {
repositories {
jcenter()
google()
}
}
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
#Sat Jan 27 10:39:10 PST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

0 comments on commit e058883

Please sign in to comment.