From 4ea05ab1008884582a28fa689bff68566f86d63c Mon Sep 17 00:00:00 2001 From: Jason Yang Date: Wed, 22 Jun 2016 13:55:36 +0800 Subject: [PATCH 1/4] Update build gradles. --- DateTimePickerLibrary/build.gradle | 11 ++++++----- DateTimePickerSamples/build.gradle | 11 +++++++---- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/DateTimePickerLibrary/build.gradle b/DateTimePickerLibrary/build.gradle index 5b6150a..778e23d 100644 --- a/DateTimePickerLibrary/build.gradle +++ b/DateTimePickerLibrary/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 23 - buildToolsVersion "23.0.3" + compileSdkVersion 24 + buildToolsVersion "24.0.0" defaultConfig { minSdkVersion 16 - targetSdkVersion 23 + targetSdkVersion 24 } compileOptions { @@ -16,6 +16,7 @@ android { } dependencies { - compile 'com.android.support:support-v4:23.3.0' - compile 'com.android.support:appcompat-v7:23.3.0' + compile 'com.android.support:support-v4:24.0.0@aar' + compile 'com.android.support:appcompat-v7:24.0.0@aar' + compile 'com.android.support:support-annotations:24.0.0' } diff --git a/DateTimePickerSamples/build.gradle b/DateTimePickerSamples/build.gradle index 69e137c..5fa50ac 100644 --- a/DateTimePickerSamples/build.gradle +++ b/DateTimePickerSamples/build.gradle @@ -1,15 +1,16 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 23 - buildToolsVersion "22.0.3" + compileSdkVersion 24 + buildToolsVersion "24.0.0" defaultConfig { applicationId "io.doist.datetimepicker.sample" minSdkVersion 16 - targetSdkVersion 23 + targetSdkVersion 24 versionCode 1 versionName "1.0" + vectorDrawables.useSupportLibrary = true } buildTypes { release { @@ -23,5 +24,7 @@ dependencies { compile project(':DateTimePickerLibrary') compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:22.0.0' + compile 'com.android.support:appcompat-v7:24.0.0@aar' + compile 'com.android.support:support-vector-drawable:24.0.0@aar' + compile 'com.android.support:animated-vector-drawable:24.0.0@aar' } diff --git a/build.gradle b/build.gradle index d3ff69d..e220f0b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:2.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0c71e76..4c74aab 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ 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-2.14-all.zip From 216b49da5cd91b6be6e5f68be853a44cdc74db33 Mon Sep 17 00:00:00 2001 From: Jason Yang Date: Wed, 22 Jun 2016 13:57:14 +0800 Subject: [PATCH 2/4] Add am/pm circles on TimePicker. --- .../time/RadialTimePickerView.java | 243 +++++++++++++++--- .../src/main/res/values/strings.xml | 3 + 2 files changed, 208 insertions(+), 38 deletions(-) diff --git a/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java b/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java index de715ba..6dd1203 100644 --- a/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java +++ b/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java @@ -44,6 +44,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.widget.TextView; +import java.text.DateFormatSymbols; import java.util.ArrayList; import java.util.Calendar; import java.util.List; @@ -181,6 +182,28 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private boolean mInputEnabled = true; + private static final int AMPM_INDEX = 2; + private static final int ENABLE_PICKER_INDEX =3; + + private float mAmPmCircleRadiusMultiplier; + + private final Paint mAmPmPaint = new Paint(); + private int mSelectedAlpha; + private int mSelectedColor; + private int mUnselectedColor; + private int mAmPmTextColor; + private int mTouchedColor; + + private String mAmText; + private String mPmText; + + private boolean mDrawValuesReady = false; + private int mAmPmCircleRadius; + private int mAmXCenter; + private int mPmXCenter; + private int mAmPmYCenter; + private int mAmOrPmPressed = -1; + public interface OnValueSelectedListener { void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance); } @@ -338,46 +361,39 @@ public RadialTimePickerView(Context context, AttributeSet attrs, int defStyleAtt mPaintCenter.setAntiAlias(true); mPaintCenter.setTextAlign(Paint.Align.CENTER); + int selectorColor = a.getColor(R.styleable.TimePicker_numbersSelectorColor, + res.getColor(R.color.timepicker_default_selector_color_material)); + mPaintSelector[HOURS][SELECTOR_CIRCLE] = new Paint(); mPaintSelector[HOURS][SELECTOR_CIRCLE].setAntiAlias(true); - mColorSelector[HOURS][SELECTOR_CIRCLE] = a.getColor( - R.styleable.TimePicker_numbersSelectorColor, - R.color.timepicker_default_selector_color_material); + mColorSelector[HOURS][SELECTOR_CIRCLE] = selectorColor; mPaintSelector[HOURS][SELECTOR_DOT] = new Paint(); mPaintSelector[HOURS][SELECTOR_DOT].setAntiAlias(true); - mColorSelector[HOURS][SELECTOR_DOT] = a.getColor( - R.styleable.TimePicker_numbersSelectorColor, - R.color.timepicker_default_selector_color_material); + mColorSelector[HOURS][SELECTOR_DOT] = selectorColor; mPaintSelector[HOURS][SELECTOR_LINE] = new Paint(); mPaintSelector[HOURS][SELECTOR_LINE].setAntiAlias(true); mPaintSelector[HOURS][SELECTOR_LINE].setStrokeWidth(2); - mColorSelector[HOURS][SELECTOR_LINE] = a.getColor( - R.styleable.TimePicker_numbersSelectorColor, - R.color.timepicker_default_selector_color_material); + mColorSelector[HOURS][SELECTOR_LINE] = selectorColor; mPaintSelector[MINUTES][SELECTOR_CIRCLE] = new Paint(); mPaintSelector[MINUTES][SELECTOR_CIRCLE].setAntiAlias(true); - mColorSelector[MINUTES][SELECTOR_CIRCLE] = a.getColor( - R.styleable.TimePicker_numbersSelectorColor, - R.color.timepicker_default_selector_color_material); + mColorSelector[MINUTES][SELECTOR_CIRCLE] = selectorColor; mPaintSelector[MINUTES][SELECTOR_DOT] = new Paint(); mPaintSelector[MINUTES][SELECTOR_DOT].setAntiAlias(true); - mColorSelector[MINUTES][SELECTOR_DOT] = a.getColor( - R.styleable.TimePicker_numbersSelectorColor, - R.color.timepicker_default_selector_color_material); + mColorSelector[MINUTES][SELECTOR_DOT] = selectorColor; mPaintSelector[MINUTES][SELECTOR_LINE] = new Paint(); mPaintSelector[MINUTES][SELECTOR_LINE].setAntiAlias(true); mPaintSelector[MINUTES][SELECTOR_LINE].setStrokeWidth(2); - mColorSelector[MINUTES][SELECTOR_LINE] = a.getColor( - R.styleable.TimePicker_numbersSelectorColor, - R.color.timepicker_default_selector_color_material); + mColorSelector[MINUTES][SELECTOR_LINE] = selectorColor; - mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor, - res.getColor(R.color.timepicker_default_numbers_background_color_material))); + int bgColor = a.getColor(R.styleable.TimePicker_numbersBackgroundColor, + res.getColor(R.color.timepicker_default_numbers_background_color_material)); + + mPaintBackground.setColor(bgColor); mPaintBackground.setAntiAlias(true); if (DEBUG) { @@ -414,6 +430,22 @@ public RadialTimePickerView(Context context, AttributeSet attrs, int defStyleAtt mSelectionRadiusMultiplier = Float.parseFloat( res.getString(R.string.timepicker_selection_radius_multiplier)); + mAmPmCircleRadiusMultiplier = Float.parseFloat( + res.getString(R.string.timepicker_ampm_circle_radius_multiplier)); + + mAmPmPaint.setTypeface(mTypeface); + mAmPmPaint.setAntiAlias(true); + mAmPmPaint.setTextAlign(Paint.Align.CENTER); + + mSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor, selectorColor); + mTouchedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor, selectorColor); + mUnselectedColor = a.getColor(R.styleable.TimePicker_amPmBackgroundColor, bgColor); + mAmPmTextColor = a.getColor(R.styleable.TimePicker_amPmTextColor, numbersTextColor); + + String[] amPmTexts = new DateFormatSymbols().getAmPmStrings(); + mAmText = amPmTexts[0]; + mPmText = amPmTexts[1]; + a.recycle(); setOnTouchListener(this); @@ -689,6 +721,8 @@ private void initData() { mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE); mAlphaSelector[MINUTES][SELECTOR_LINE].setValue( mShowHours ? ALPHA_TRANSPARENT : ALPHA_SELECTOR); + + mSelectedAlpha = ALPHA_SELECTOR; } @Override @@ -760,6 +794,10 @@ public void onDraw(Canvas canvas) { drawCenter(canvas); + if (!mIs24HourMode) { + drawAmPmCircle(canvas); + } + if (DEBUG) { drawDebug(canvas); } @@ -767,6 +805,68 @@ public void onDraw(Canvas canvas) { canvas.restore(); } + private void drawAmPmCircle(Canvas canvas) { + int viewWidth = getWidth(); + if (viewWidth == 0) { + return; + } + + if (!mDrawValuesReady) { + int layoutXCenter = getWidth() / 2; + int layoutYCenter = getHeight() / 2; + int circleRadius = + (int) (Math.min(layoutXCenter, layoutYCenter) * mCircleRadiusMultiplier[HOURS]); + mAmPmCircleRadius = (int) (circleRadius * mAmPmCircleRadiusMultiplier); + layoutYCenter += mAmPmCircleRadius * 0.75; + int textSize = mAmPmCircleRadius * 3 / 4; + mAmPmPaint.setTextSize(textSize); + + // Line up the vertical center of the AM/PM circles with the bottom of the main circle. + mAmPmYCenter = layoutYCenter - mAmPmCircleRadius + circleRadius; + // Line up the horizontal edges of the AM/PM circles with the horizontal edges + // of the main circle. + mAmXCenter = layoutXCenter - circleRadius + mAmPmCircleRadius / 2; + mPmXCenter = layoutXCenter + circleRadius - mAmPmCircleRadius / 2; + + mDrawValuesReady = true; + } + + // We'll need to draw either a lighter blue (for selection), a darker blue (for touching) + // or white (for not selected). + int amColor = mUnselectedColor; + int amAlpha = Color.alpha(mUnselectedColor); + int pmColor = mUnselectedColor; + int pmAlpha = Color.alpha(mUnselectedColor); + if (mAmOrPm == AM) { + amColor = mSelectedColor; + amAlpha = mSelectedAlpha; + } else if (mAmOrPm == PM) { + pmColor = mSelectedColor; + pmAlpha = mSelectedAlpha; + } + if (mAmOrPmPressed == AM) { + amColor = mTouchedColor; + amAlpha = Color.alpha(mTouchedColor); + } else if (mAmOrPmPressed == PM) { + pmColor = mTouchedColor; + pmAlpha = Color.alpha(mTouchedColor); + } + + // Draw the two circles. + mAmPmPaint.setColor(amColor); + mAmPmPaint.setAlpha(amAlpha); + canvas.drawCircle(mAmXCenter, mAmPmYCenter, mAmPmCircleRadius, mAmPmPaint); + mAmPmPaint.setColor(pmColor); + mAmPmPaint.setAlpha(pmAlpha); + canvas.drawCircle(mPmXCenter, mAmPmYCenter, mAmPmCircleRadius, mAmPmPaint); + + // Draw the AM/PM texts on top. + mAmPmPaint.setColor(mAmPmTextColor); + int textYCenter = mAmPmYCenter - (int) (mAmPmPaint.descent() + mAmPmPaint.ascent()) / 2; + canvas.drawText(mAmText, mAmXCenter, textYCenter, mAmPmPaint); + canvas.drawText(mPmText, mPmXCenter, textYCenter, mAmPmPaint); + } + private void drawCircleBackground(Canvas canvas) { canvas.drawCircle(mXCenter, mYCenter, mCircleRadius[HOURS], mPaintBackground); } @@ -1195,35 +1295,79 @@ private int getDegreesFromXY(float x, float y) { } boolean mChangedDuringTouch = false; + private int mIsTouchingAmOrPm = -1; @Override public boolean onTouch(View v, MotionEvent event) { - if (!mInputEnabled) { - return true; - } final int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_MOVE - || action == MotionEvent.ACTION_UP - || action == MotionEvent.ACTION_DOWN) { - boolean forceSelection = false; - boolean autoAdvance = false; - - if (action == MotionEvent.ACTION_DOWN) { + boolean forceSelection = false; + boolean autoAdvance = false; + + float eventX = event.getX(); + float eventY = event.getY(); + mIsTouchingAmOrPm = !mIs24HourMode ? getIsTouchingAmOrPm(eventX, eventY) : -1; + switch (action) { + case MotionEvent.ACTION_DOWN: { + if (!mInputEnabled) { + return true; + } // This is a new event stream, reset whether the value changed. mChangedDuringTouch = false; - } else if (action == MotionEvent.ACTION_UP) { - autoAdvance = true; - // If we saw a down/up pair without the value changing, assume - // this is a single-tap selection and force a change. - if (!mChangedDuringTouch) { - forceSelection = true; + if (mIsTouchingAmOrPm == AM || mIsTouchingAmOrPm == PM) { + mAmOrPmPressed = mIsTouchingAmOrPm; + invalidate(); + } else { + mChangedDuringTouch |= handleTouchInput( + event.getX(), event.getY(), forceSelection, autoAdvance); + } + break; + } + case MotionEvent.ACTION_MOVE: { + if (!mInputEnabled) { + return true; + } + if (mIsTouchingAmOrPm == AM || mIsTouchingAmOrPm == PM) { + mAmOrPmPressed = mIsTouchingAmOrPm; + invalidate(); + } else { + mAmOrPmPressed = -1; + invalidate(); + mChangedDuringTouch |= handleTouchInput( + event.getX(), event.getY(), forceSelection, autoAdvance); } + break; } + case MotionEvent.ACTION_UP: { + if (!mInputEnabled) { + mListener.onValueSelected(ENABLE_PICKER_INDEX, 1, false); + return true; + } + if (mIsTouchingAmOrPm == AM || mIsTouchingAmOrPm == PM) { + mAmOrPmPressed = -1; + invalidate(); + + if (mIsTouchingAmOrPm != mAmOrPm) { + setAmOrPm(mIsTouchingAmOrPm); + mListener.onValueSelected(AMPM_INDEX, mIsTouchingAmOrPm, false); + } - mChangedDuringTouch |= handleTouchInput( - event.getX(), event.getY(), forceSelection, autoAdvance); + mIsTouchingAmOrPm = -1; + } else { + autoAdvance = true; + + // If we saw a down/up pair without the value changing, assume + // this is a single-tap selection and force a change. + if (!mChangedDuringTouch) { + forceSelection = true; + } + mChangedDuringTouch |= handleTouchInput( + event.getX(), event.getY(), forceSelection, autoAdvance); + } + break; + } + default: } return true; @@ -1293,6 +1437,29 @@ public void setInputEnabled(boolean inputEnabled) { invalidate(); } + private int getIsTouchingAmOrPm(float xCoord, float yCoord) { + if (!mDrawValuesReady) { + return -1; + } + + int squaredYDistance = (int) ((yCoord - mAmPmYCenter) * (yCoord - mAmPmYCenter)); + + int distanceToAmCenter = + (int) Math.sqrt((xCoord - mAmXCenter) * (xCoord - mAmXCenter) + squaredYDistance); + if (distanceToAmCenter <= mAmPmCircleRadius) { + return AM; + } + + int distanceToPmCenter = + (int) Math.sqrt((xCoord - mPmXCenter) * (xCoord - mPmXCenter) + squaredYDistance); + if (distanceToPmCenter <= mAmPmCircleRadius) { + return PM; + } + + // Neither was close enough. + return -1; + } + private class RadialPickerTouchHelper extends ExploreByTouchHelper { private final Rect mTempRect = new Rect(); diff --git a/DateTimePickerLibrary/src/main/res/values/strings.xml b/DateTimePickerLibrary/src/main/res/values/strings.xml index 9fcc135..1ee637c 100644 --- a/DateTimePickerLibrary/src/main/res/values/strings.xml +++ b/DateTimePickerLibrary/src/main/res/values/strings.xml @@ -52,4 +52,7 @@ sans-serif + + + 0.22 From a74783fdb75b5a53bdd524809189ae6369e2f4a9 Mon Sep 17 00:00:00 2001 From: Jason Yang Date: Wed, 22 Jun 2016 13:59:54 +0800 Subject: [PATCH 3/4] Let isTouchingAmOrPm be a local variable. --- .../time/RadialTimePickerView.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java b/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java index 6dd1203..977071d 100644 --- a/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java +++ b/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java @@ -1295,7 +1295,6 @@ private int getDegreesFromXY(float x, float y) { } boolean mChangedDuringTouch = false; - private int mIsTouchingAmOrPm = -1; @Override public boolean onTouch(View v, MotionEvent event) { @@ -1306,7 +1305,9 @@ public boolean onTouch(View v, MotionEvent event) { float eventX = event.getX(); float eventY = event.getY(); - mIsTouchingAmOrPm = !mIs24HourMode ? getIsTouchingAmOrPm(eventX, eventY) : -1; + + int isTouchingAmOrPm = !mIs24HourMode ? getIsTouchingAmOrPm(eventX, eventY) : -1; + switch (action) { case MotionEvent.ACTION_DOWN: { if (!mInputEnabled) { @@ -1315,8 +1316,8 @@ public boolean onTouch(View v, MotionEvent event) { // This is a new event stream, reset whether the value changed. mChangedDuringTouch = false; - if (mIsTouchingAmOrPm == AM || mIsTouchingAmOrPm == PM) { - mAmOrPmPressed = mIsTouchingAmOrPm; + if (isTouchingAmOrPm == AM || isTouchingAmOrPm == PM) { + mAmOrPmPressed = isTouchingAmOrPm; invalidate(); } else { mChangedDuringTouch |= handleTouchInput( @@ -1328,8 +1329,8 @@ public boolean onTouch(View v, MotionEvent event) { if (!mInputEnabled) { return true; } - if (mIsTouchingAmOrPm == AM || mIsTouchingAmOrPm == PM) { - mAmOrPmPressed = mIsTouchingAmOrPm; + if (isTouchingAmOrPm == AM || isTouchingAmOrPm == PM) { + mAmOrPmPressed = isTouchingAmOrPm; invalidate(); } else { mAmOrPmPressed = -1; @@ -1344,16 +1345,14 @@ public boolean onTouch(View v, MotionEvent event) { mListener.onValueSelected(ENABLE_PICKER_INDEX, 1, false); return true; } - if (mIsTouchingAmOrPm == AM || mIsTouchingAmOrPm == PM) { + if (isTouchingAmOrPm == AM || isTouchingAmOrPm == PM) { mAmOrPmPressed = -1; invalidate(); - if (mIsTouchingAmOrPm != mAmOrPm) { - setAmOrPm(mIsTouchingAmOrPm); - mListener.onValueSelected(AMPM_INDEX, mIsTouchingAmOrPm, false); + if (isTouchingAmOrPm != mAmOrPm) { + setAmOrPm(isTouchingAmOrPm); + mListener.onValueSelected(AMPM_INDEX, isTouchingAmOrPm, false); } - - mIsTouchingAmOrPm = -1; } else { autoAdvance = true; From bb325eccee0981b031ba9fda5749b2fb9f1e8d05 Mon Sep 17 00:00:00 2001 From: Jason Yang Date: Thu, 23 Jun 2016 10:25:52 +0800 Subject: [PATCH 4/4] Add comment on index constants. --- .../io/doist/datetimepicker/time/RadialTimePickerView.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java b/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java index 977071d..b554adb 100644 --- a/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java +++ b/DateTimePickerLibrary/src/main/java/io/doist/datetimepicker/time/RadialTimePickerView.java @@ -182,8 +182,12 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private boolean mInputEnabled = true; + // NOT a real index for the purpose of what's showing. + // See TimePickerClockDelegate.AMPM_INDEX. private static final int AMPM_INDEX = 2; - private static final int ENABLE_PICKER_INDEX =3; + // Also NOT a real index, just used for keyboard mode. + // See TimePickerClockDelegate.ENABLE_PICKER_INDEX. + private static final int ENABLE_PICKER_INDEX = 3; private float mAmPmCircleRadiusMultiplier;