diff --git a/library/src/main/java/com/alamkanak/weekview/WeekView.java b/library/src/main/java/com/alamkanak/weekview/WeekView.java index 9882f8f45..e1d3e193e 100755 --- a/library/src/main/java/com/alamkanak/weekview/WeekView.java +++ b/library/src/main/java/com/alamkanak/weekview/WeekView.java @@ -5,6 +5,7 @@ import android.graphics.*; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import androidx.core.graphics.drawable.DrawableCompat; import android.os.Build; import androidx.annotation.NonNull; @@ -79,6 +80,39 @@ private enum AutoScrollDirection { private Paint mTodayHeaderTextPaint; private Paint mEventBackgroundPaint; private Paint mNewEventBackgroundPaint; + private TextPaint mTagTextPaint; + private Paint mTagBackgroundPaint; + private Xfermode mXfermode; + private int mTagIconSize = 96; + private int mTagIconSpacing = 12; + private int mTagCornerRadius = 12; + + private static final Map TAG_ICON_MAP = new HashMap() {{ + put("meeting", R.drawable.tag_meeting); + put("birthday", R.drawable.tag_birthday); + put("deadline", R.drawable.tag_deadline); + }}; + + public void setTagIconSize(int sizePx) { + mTagIconSize = sizePx; + } + public void setTagIconSpacing(int spacingPx) { + mTagIconSpacing = spacingPx; + } + public int getTagIconSize() { + return mTagIconSize; + } + public int getTagIconSpacing() { + return mTagIconSpacing; + } + public int getTagCornerRadius() { + return mTagCornerRadius; + } + public void setTagCornerRadius(int tagCornerRadius) { + mTagCornerRadius = tagCornerRadius; + } + + private float mHeaderColumnWidth; private List mEventRects; private List mEvents; @@ -561,6 +595,21 @@ private void init() { // Set default empty event color. mNewEventColor = Color.parseColor("#3c93d9"); + // Initialize paint for tags + mTagBackgroundPaint = new Paint(); + mTagBackgroundPaint.setColor(Color.WHITE); + mTagBackgroundPaint.setStyle(Paint.Style.FILL); + + mTagTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + mTagTextPaint.setColor(Color.BLACK); // This color will be used to "punch out" the background + mTagTextPaint.setTextSize(mEventTextSize); + mTagTextPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); + // Copy other relevant properties from mEventTextPaint if needed + // mTagTextPaint.setTypeface(mEventTextPaint.getTypeface()); + + // This Xfermode will create the "punch-out" effect + mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT); + mScaleDetector = new ScaleGestureDetector(mContext, new WeekViewGestureListener()); } @@ -1153,7 +1202,14 @@ private void drawEventTitle(WeekViewEvent event, RectF rect, Canvas canvas, floa bob.append(event.getLocation()); } - int availableHeight = (int) (rect.bottom - originalTop - mEventPadding * 2); + // Reserve space for tag icons + int iconRowHeight = 0; + List tags = event.getTags(); + if (tags != null && !tags.isEmpty()) { + iconRowHeight = mTagIconSize + mTagIconSpacing; + } + + int availableHeight = (int) (rect.bottom - originalTop - mEventPadding * 2 - iconRowHeight); int availableWidth = (int) (rect.right - originalLeft - mEventPadding * 2); // Get text color if necessary @@ -1186,6 +1242,102 @@ private void drawEventTitle(WeekViewEvent event, RectF rect, Canvas canvas, floa canvas.restore(); } } + + // Draw tag icons row + if (tags != null && !tags.isEmpty()) { + drawTags(tags, rect, canvas, originalLeft, rect.bottom - mTagIconSize - mTagIconSpacing); + } + } + + // Helper to get drawable for a tag + private Drawable getTagIconDrawable(String tag) { + Integer resId = TAG_ICON_MAP.get(tag); + if (resId == null) return null; + try { + return getResources().getDrawable(resId); + } catch (Exception e) { + return null; + } + } + + // Draw tags + private void drawTags(List tags, RectF rect, Canvas canvas, float left, float bottomY) { + canvas.save(); + canvas.clipRect(rect); + float startX = left + mTagIconSpacing; + for (int i = 0; i < tags.size() - 1; i = i + 2) { + String tag = tags.get(i); + String color = tags.get(i + 1); + Drawable icon = getTagIconDrawable(tag); + if (icon != null) { + DrawableCompat.setTint(icon, Color.parseColor(color)); + icon.setBounds((int) (startX), (int) bottomY, (int) (startX + mTagIconSize), (int) (bottomY + mTagIconSize)); + icon.draw(canvas); + startX += mTagIconSize + mTagIconSpacing; + } else if (!TextUtils.isEmpty(tag)) { + // Check if the string is only emojis + boolean isOnlyEmoji = tag.matches("^[\\p{IsEmoji_Presentation}\\p{IsEmoji_Modifier_Base}\\p{IsEmoji_Component}\\u200d\\uFE0F]+$") && !tag.matches(".*\\d.*"); + + // Measure the text + float textWidth = mTagTextPaint.measureText(tag); + float tagPadding = mEventPadding / 2; + + if (isOnlyEmoji) { + // --- EMOJI ONLY PATH --- + // Just draw the emoji in its original colors, no background + mTagTextPaint.setXfermode(null); // Ensure no Xfermode is active + + StaticLayout textLayout = StaticLayout.Builder.obtain(tag, 0, tag.length(), mTagTextPaint, (int) Math.ceil(textWidth)) + .setAlignment(Layout.Alignment.ALIGN_NORMAL) + .setIncludePad(false) + .build(); + + canvas.save(); + // Align emoji vertically with where the icon/background would be + float textY = bottomY + (mTagIconSize - textLayout.getHeight()) / 2; + canvas.translate(startX, textY); + textLayout.draw(canvas); + canvas.restore(); + + startX += textWidth + mTagIconSpacing; + + } else { + // --- STANDARD TEXT PATH (PUNCH-OUT EFFECT) --- + float backgroundHeight = mTagIconSize; + float backgroundWidth = textWidth + tagPadding * 2; + RectF backgroundRect = new RectF(startX, bottomY, startX + backgroundWidth, bottomY + backgroundHeight); + + // Save layer for Xfermode composition + int saveCount = canvas.saveLayer(backgroundRect, null); + + // 1. Draw the solid background + mTagBackgroundPaint.setColor(Color.parseColor(color)); + canvas.drawRoundRect(backgroundRect, mTagCornerRadius, mTagCornerRadius, mTagBackgroundPaint); + + // 2. Set Xfermode to DST_OUT to punch out the text + mTagTextPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + + StaticLayout textLayout = StaticLayout.Builder.obtain(tag, 0, tag.length(), mTagTextPaint, (int) Math.ceil(textWidth)) + .setAlignment(Layout.Alignment.ALIGN_NORMAL) + .setIncludePad(false) + .build(); + + canvas.save(); + float textY = backgroundRect.top + (backgroundHeight - textLayout.getHeight()) / 2; + float textX = backgroundRect.left + tagPadding; + canvas.translate(textX, textY); + textLayout.draw(canvas); + canvas.restore(); + + // 3. Cleanup + mTagTextPaint.setXfermode(null); + canvas.restoreToCount(saveCount); + + startX += backgroundWidth + mTagIconSpacing; + } + } + } + canvas.restore(); } /** diff --git a/library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java b/library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java index 8fbad5431..0589b228e 100644 --- a/library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java +++ b/library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java @@ -24,11 +24,13 @@ public class WeekViewEvent { int mColor; private boolean mAllDay; private Shader mShader; + private List mTags = new ArrayList<>(); public WeekViewEvent() { } + /** * Initializes the event for week view. * @@ -220,6 +222,15 @@ public void setEndTime(Calendar endTime) { this.mEndTime = endTime; } + public List getTags() { + return mTags; + } + + public void setTags(List tags) { + this.mTags = tags != null ? tags : new ArrayList<>(); + } + + public String getName() { return mName; } diff --git a/library/src/main/res/drawable/tag_birthday.xml b/library/src/main/res/drawable/tag_birthday.xml new file mode 100644 index 000000000..0436cc122 --- /dev/null +++ b/library/src/main/res/drawable/tag_birthday.xml @@ -0,0 +1,9 @@ + + + diff --git a/library/src/main/res/drawable/tag_deadline.xml b/library/src/main/res/drawable/tag_deadline.xml new file mode 100644 index 000000000..0436cc122 --- /dev/null +++ b/library/src/main/res/drawable/tag_deadline.xml @@ -0,0 +1,9 @@ + + + diff --git a/library/src/main/res/drawable/tag_meeting.xml b/library/src/main/res/drawable/tag_meeting.xml new file mode 100644 index 000000000..0436cc122 --- /dev/null +++ b/library/src/main/res/drawable/tag_meeting.xml @@ -0,0 +1,9 @@ + + +