diff --git a/build.gradle b/build.gradle index bd1e1fd48..69c07d996 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.5.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -19,5 +20,6 @@ allprojects { repositories { jcenter() + google() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 66b2b75d1..d271cafc1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Aug 06 18:02:35 CEST 2017 +#Sat Feb 01 16:17:02 CET 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/library/build.gradle b/library/build.gradle index a9291dd32..8246604d7 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -5,12 +5,12 @@ repositories { } android { - compileSdkVersion 25 - buildToolsVersion '25.0.2' + compileSdkVersion 28 + buildToolsVersion '28.0.3' defaultConfig { - minSdkVersion 9 - targetSdkVersion 25 + minSdkVersion 14 + targetSdkVersion 28 } } @@ -18,8 +18,8 @@ configurations { javadocDeps } dependencies { - compile 'com.android.support:appcompat-v7:25.1.0' - javadocDeps 'com.android.support:appcompat-v7:25.1.0' + implementation 'com.android.support:appcompat-v7:28.0.0' + javadocDeps 'com.android.support:appcompat-v7:28.0.0' } apply from: 'gradle-mvn-push.gradle' \ No newline at end of file diff --git a/library/src/main/java/com/alamkanak/weekview/WeekView.java b/library/src/main/java/com/alamkanak/weekview/WeekView.java index a44062861..f7b90f408 100755 --- a/library/src/main/java/com/alamkanak/weekview/WeekView.java +++ b/library/src/main/java/com/alamkanak/weekview/WeekView.java @@ -2,7 +2,14 @@ import android.content.Context; import android.content.res.TypedArray; -import android.graphics.*; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; @@ -11,18 +18,37 @@ import android.support.v4.view.GestureDetectorCompat; import android.support.v4.view.ViewCompat; import android.support.v4.view.animation.FastOutLinearInInterpolator; -import android.text.*; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; import android.text.format.DateFormat; import android.text.style.StyleSpan; import android.util.AttributeSet; import android.util.TypedValue; -import android.view.*; +import android.view.DragEvent; +import android.view.GestureDetector; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.ViewConfiguration; import android.widget.OverScroller; import java.text.SimpleDateFormat; -import java.util.*; - -import static com.alamkanak.weekview.WeekViewUtil.*; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +import static com.alamkanak.weekview.WeekViewUtil.daysBetween; +import static com.alamkanak.weekview.WeekViewUtil.getPassedMinutesInDay; +import static com.alamkanak.weekview.WeekViewUtil.isSameDay; +import static com.alamkanak.weekview.WeekViewUtil.today; /** * Created by Raquib-ul-Alam Kanak on 7/21/2014. @@ -38,6 +64,12 @@ private enum Direction { public static final int LENGTH_SHORT = 1; @Deprecated public static final int LENGTH_LONG = 2; + + public static final int ADDITIONAL_INFO_NONE = 0; + public static final int ADDITIONAL_INFO_YEAR = 1; + public static final int ADDITIONAL_INFO_MONTH = 2; + public static final int ADDITIONAL_INFO_WEEK = 3; + private final Context mContext; private Calendar mHomeDate; private Calendar mMinDate; @@ -147,6 +179,7 @@ private enum Direction { private boolean mAutoLimitTime = false; private boolean mEnableDropListener = false; private int mMinOverlappingMinutes = 0; + private int mAdditionalTimeInfo = ADDITIONAL_INFO_NONE; // Listeners. private EventClickListener mEventClickListener; @@ -350,7 +383,7 @@ left < getWidth() && top < getHeight() && right > mHeaderColumnWidth && bottom > 0 - ) { + ) { RectF dayRectF = new RectF(left, top, right, bottom - mCurrentOrigin.y); newEvent.setColor(mNewEventColor); mNewEventRect = new EventRect(newEvent, newEvent, dayRectF); @@ -709,7 +742,7 @@ private void drawTimeColumnAndAxes(Canvas canvas) { canvas.save(); canvas.clipRect(0, mHeaderHeight + mHeaderRowPadding * 2, mHeaderColumnWidth, getHeight()); canvas.restore(); - + for (int i = 0; i < getNumberOfPeriods(); i++) { // If we are showing half hours (eg. 5:30am), space the times out by half the hour height // and need to provide 30 minutes on each odd period, otherwise, minutes is always 0. @@ -929,7 +962,7 @@ else if (mNewHourHeight > mMaxHourHeight) canvas.clipRect(0, 0, mTimeTextWidth + mHeaderColumnPadding * 2, mHeaderHeight + mHeaderRowPadding * 2); canvas.drawRect(0, 0, mTimeTextWidth + mHeaderColumnPadding * 2, mHeaderHeight + mHeaderRowPadding * 2, mHeaderBackgroundPaint); canvas.restore(); - + // Clip to paint header row only. canvas.save(); canvas.clipRect(mHeaderColumnWidth, 0, getWidth(), mHeaderHeight + mHeaderRowPadding * 2); @@ -940,6 +973,7 @@ else if (mNewHourHeight > mMaxHourHeight) // Draw the header row texts. startPixel = startFromPixel; + drawAdditionalInfo(canvas, leftDaysWithGaps, startPixel); for (int dayNumber = leftDaysWithGaps + 1; dayNumber <= leftDaysWithGaps + getRealNumberOfVisibleDays() + 1; dayNumber++) { // Check if the day is today. day = (Calendar) mHomeDate.clone(); @@ -961,6 +995,27 @@ else if (mNewHourHeight > mMaxHourHeight) } + private void drawAdditionalInfo(Canvas canvas, int leftDaysWithGaps, float startPixel) { + if (mAdditionalTimeInfo != ADDITIONAL_INFO_NONE) { + String pattern; + switch (mAdditionalTimeInfo) { + case ADDITIONAL_INFO_MONTH: + pattern = "MMM"; + break; + case ADDITIONAL_INFO_WEEK: + pattern = "ww"; + break; + default: + pattern = "yyyy"; + break; + } + Calendar firstVisibleDay = (Calendar) mHomeDate.clone(); + firstVisibleDay.add(Calendar.DATE, leftDaysWithGaps); + canvas.drawText(new SimpleDateFormat(pattern, Locale.getDefault()).format(firstVisibleDay.getTime()), + startPixel - mHeaderColumnWidth / 2, mHeaderTextHeight + mHeaderRowPadding, mHeaderTextPaint); + } + } + /** * Get the time and date where the user clicked on. * @@ -1070,7 +1125,7 @@ left < getWidth() && top < getHeight() && right > mHeaderColumnWidth && bottom > mHeaderHeight + mHeaderRowPadding * 2 + mTimeTextHeight / 2 + mHeaderMarginBottom - ) { + ) { mEventRects.get(i).rectF = new RectF(left, top, right, bottom); mEventBackgroundPaint.setColor(mEventRects.get(i).event.getColor() == 0 ? mDefaultEventColor : mEventRects.get(i).event.getColor()); mEventBackgroundPaint.setShader(mEventRects.get(i).event.getShader()); @@ -1123,7 +1178,7 @@ left < getWidth() && top < getHeight() && right > mHeaderColumnWidth && bottom > 0 - ) { + ) { mEventRects.get(i).rectF = new RectF(left, top, right, bottom); mEventBackgroundPaint.setColor(mEventRects.get(i).event.getColor() == 0 ? mDefaultEventColor : mEventRects.get(i).event.getColor()); mEventBackgroundPaint.setShader(mEventRects.get(i).event.getShader()); @@ -1149,11 +1204,13 @@ private void drawEventTitle(WeekViewEvent event, RectF rect, Canvas canvas, floa if (rect.right - rect.left - mEventPadding * 2 < 0) return; if (rect.bottom - rect.top - mEventPadding * 2 < 0) return; + + if (mNewEventIdentifier.equals(event.getIdentifier())) return; + // Prepare the name of the event. - SpannableStringBuilder bob = new SpannableStringBuilder(); + StringBuilder bob = new StringBuilder(); if (!TextUtils.isEmpty(event.getName())) { bob.append(event.getName()); - bob.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, bob.length(), 0); } // Prepare the location of the event. if (!TextUtils.isEmpty(event.getLocation())) { @@ -1174,27 +1231,56 @@ private void drawEventTitle(WeekViewEvent event, RectF rect, Canvas canvas, floa if (textLayout.getLineCount() > 0) { int lineHeight = textLayout.getHeight() / textLayout.getLineCount(); - if (availableHeight >= lineHeight) { - // Calculate available number of line counts. - int availableLineCount = availableHeight / lineHeight; - do { - // Ellipsize text to fit into event rect. - if (!mNewEventIdentifier.equals(event.getIdentifier())) - textLayout = new StaticLayout(TextUtils.ellipsize(bob, mEventTextPaint, availableLineCount * availableWidth, TextUtils.TruncateAt.END), mEventTextPaint, (int) (rect.right - originalLeft - mEventPadding * 2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - - // Reduce line count. - availableLineCount--; - - // Repeat until text is short enough. - } while (textLayout.getHeight() > availableHeight); - - // Draw text. - canvas.save(); - canvas.translate(originalLeft + mEventPadding, originalTop + mEventPadding); - textLayout.draw(canvas); - canvas.restore(); + if (availableHeight < lineHeight) { + return; + } + String text = textLayout.getText().toString(); + SpannableStringBuilder correctedText = getEllipsizedText(text, rect, originalLeft, availableHeight, availableWidth, lineHeight); + + boolean wholeNameIsShown = correctedText.toString().startsWith(event.getName()); + // make event name bold + if (wholeNameIsShown) { + correctedText.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, event.getName().length(), 0); + } else { // text must be ellipsized and the location (if any) is totally cut of + correctedText.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, correctedText.length(), 0); + } + + textLayout = new StaticLayout(correctedText, mEventTextPaint, (int) (rect.right - originalLeft - mEventPadding * 2), + Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + + // Draw text. + canvas.save(); + canvas.translate(originalLeft + mEventPadding, originalTop + mEventPadding); + textLayout.draw(canvas); + canvas.restore(); + } + } + + private SpannableStringBuilder getEllipsizedText(String text, RectF rect, float originalLeft, int availableHeight, int availableWidth, int lineHeight) { + // Calculate available number of line counts. + @SuppressWarnings("UnnecessaryLocalVariable") + int availableLineCount = availableHeight / lineHeight; + int availableLinesLeft = availableLineCount; + String[] lines = text.split("\n"); + List newLines = new ArrayList<>(); + for (String s : lines) { + if (availableLinesLeft < 1) { + break; } + CharSequence ellipsizedLine = TextUtils.ellipsize( + s, + mEventTextPaint, availableWidth * availableLinesLeft, TextUtils.TruncateAt.END); + newLines.add((String) ellipsizedLine); + StaticLayout textLayout = new StaticLayout(ellipsizedLine, mEventTextPaint, (int) (rect.right - originalLeft - mEventPadding * 2), + Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + availableLinesLeft -= textLayout.getLineCount(); + } + SpannableStringBuilder correctedText = new SpannableStringBuilder(); + for (String line : newLines) { + correctedText.append(line); + correctedText.append("\n"); } + return correctedText; } /** @@ -2503,6 +2589,20 @@ public int getMinOverlappingMinutes() { return this.mMinOverlappingMinutes; } + /** + * Sets which information should be displayed in addition in the header next to the week day names + * + * @param additionalTimeInfo the info which should be displayed, one of {@literal ADDITIONAL_INFO_NONE}, + * {@literal ADDITIONAL_INFO_YEAR}, {@literal ADDITIONAL_INFO_MONTH}, {@literal ADDITIONAL_INFO_WEEK} + */ + public void setAdditionalTimeInfo(int additionalTimeInfo) { + this.mAdditionalTimeInfo = additionalTimeInfo; + } + + public int getAdditionalTimeInfo() { + return this.mAdditionalTimeInfo; + } + ///////////////////////////////////////////////////////////////// // // Functions related to scrolling. @@ -2776,6 +2876,7 @@ public interface AddEventClickListener { public interface ZoomEndListener { /** * Triggered when the user finishes a zoom action. + * * @param hourHeight The final height of hours when the user finishes zoom. */ void onZoomEnd(int hourHeight); diff --git a/sample/build.gradle b/sample/build.gradle index 23e0f47cc..2ec21997b 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion '25.0.2' + compileSdkVersion 28 + buildToolsVersion '28.0.3' defaultConfig { applicationId "com.alamkanak.weekview" minSdkVersion 14 - targetSdkVersion 25 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -20,8 +20,8 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile project(':library') - compile 'com.android.support:appcompat-v7:25.1.0' - compile 'com.squareup.retrofit:retrofit:1.9.0' + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':library') + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.squareup.retrofit:retrofit:1.9.0' }