// ===== CONFIG =====
const DOT_SIZE = 15
const DOT_SPACING_X = 6
const DOT_SPACING_Y = 6
const COLOR_DONE = "#ff7a00"
const COLOR_LEFT = "#ffffff"
const COLOR_REMINDER = "#ff0000"
const BACKGROUND = "#000000"
// ==================
let today = new Date()
let day = today.getDate()
let year = today.getFullYear()
let month = today.getMonth()
let daysInMonth = new Date(year, month + 1, 0).getDate()
// 🔥 FETCH REMINDERS
let calendars = await Calendar.forReminders()
let reminders = await Reminder.allIncomplete(calendars)
let reminderDays = new Set()
for (let r of reminders) {
if (!r.dueDate) continue
let d = new Date(r.dueDate)
if (d.getMonth() !== month || d.getFullYear() !== year) continue
if (r.recurrenceRules) {
let hasDaily = r.recurrenceRules.some(rule => rule.frequency === "daily")
if (hasDaily) continue
}
reminderDays.add(d.getDate())
}
// ==================
function makeSplitDot(size, colorL, colorR) {
let scale = 4
let s = size * scale
let ctx = new DrawContext()
ctx.size = new Size(s, s)
ctx.opaque = false
ctx.respectScreenScale = false
let cx = s / 2
let cy = s / 2
let r = s / 2
for (let x = 0; x < s; x++) {
let dx = x - cx + 0.5
if (Math.abs(dx) > r) continue
let halfH = Math.sqrt(r * r - dx * dx)
let top = cy - halfH
let height = halfH * 2
let col = (x < s / 2) ? new Color(colorL) : new Color(colorR)
ctx.setFillColor(col)
ctx.fillRect(new Rect(x, top, 1, height))
}
return ctx.getImage()
}
// ==================
let widget = new ListWidget()
widget.backgroundColor = new Color(BACKGROUND)
widget.addSpacer()
let container = widget.addStack()
container.layoutVertically()
container.centerAlignContent()
let rows = Math.ceil(daysInMonth / 7)
for (let r = 0; r < rows; r++) {
let row = container.addStack()
row.layoutHorizontally()
row.centerAlignContent()
for (let c = 0; c < 7; c++) {
let index = r * 7 + c + 1
if (index > daysInMonth) break
if (reminderDays.has(index) && index === day) {
let img = makeSplitDot(DOT_SIZE, COLOR_DONE, COLOR_REMINDER)
let dotImg = row.addImage(img)
dotImg.imageSize = new Size(DOT_SIZE * 0.80, DOT_SIZE * 0.80)
} else if (reminderDays.has(index) && index > day) {
let dot = row.addText("●")
dot.textColor = new Color(COLOR_REMINDER)
dot.font = Font.systemFont(DOT_SIZE)
} else if (index <= day) {
let dot = row.addText("●")
dot.textColor = new Color(COLOR_DONE)
dot.font = Font.systemFont(DOT_SIZE)
} else {
let dot = row.addText("●")
dot.textColor = new Color(COLOR_LEFT)
dot.font = Font.systemFont(DOT_SIZE)
}
row.addSpacer(DOT_SPACING_X)
}
container.addSpacer(DOT_SPACING_Y)
}
widget.addSpacer()
Script.setWidget(widget)
Script.complete()