Last active
February 25, 2024 12:41
-
-
Save stanleytangerror/45e61cfef2b6e049b7424829ab19286e to your computer and use it in GitHub Desktop.
Countdown widget in iOS Scriptable
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class ComingEvent { | |
| constructor(name, description, countDownTime, happenTime) { | |
| this.name = name; | |
| this.description = description || '✏️'; | |
| this.countDownTime = countDownTime; | |
| this.happenTime = happenTime; | |
| } | |
| get percentage() { | |
| var total = this.happenTime - this.countDownTime; | |
| var lasting = Date.now() - this.countDownTime; | |
| return Math.max(0, lasting / total); | |
| } | |
| get dueDate() { | |
| var formatter = new DateFormatter(); | |
| formatter.useMediumDateStyle(); | |
| return formatter.string(this.happenTime); | |
| } | |
| get remainingDays() { | |
| return Math.ceil((this.happenTime.getTime() - Date.now()) / (1000*60*60*24)); | |
| } | |
| } | |
| function DaysOffset(date, days) { | |
| return new Date(date.getTime() + days * 1000*60*60*24); | |
| } | |
| ///////////////////// | |
| let reminders = (await Reminder.allIncomplete()) | |
| .filter(reminder => { | |
| return reminder.dueDate; | |
| }); | |
| let events = reminders.map(reminder => { | |
| return new ComingEvent(reminder.title, reminder.notes, DaysOffset(reminder.dueDate, -30), reminder.dueDate); | |
| }); | |
| ////////////////////// | |
| let widget = createWidget(); | |
| Script.setWidget(widget); | |
| Script.complete(); | |
| if (config.runsInApp) { | |
| widget.presentLarge(); | |
| } | |
| ////////////////////// | |
| function createWidget() { | |
| var widget = new ListWidget(); | |
| widget.useDefaultPadding(); | |
| if (config.runsInApp) { | |
| var stack = widget.addStack(); | |
| stack.layoutHorizontally(); | |
| drawEventList(stack, events.slice(0, 4)); | |
| stack.addSpacer(); | |
| drawEventList(stack, events.slice(4, 8)); | |
| } | |
| if (config.runsInWidget) { | |
| if (config.widgetFamily === 'small') { | |
| var stack = widget.addStack(); | |
| stack.layoutHorizontally(); | |
| drawEventList(stack, events.slice(0, 4)); | |
| } | |
| if (config.widgetFamily === 'medium') { | |
| var stack = widget.addStack(); | |
| stack.layoutHorizontally(); | |
| drawEventList(stack, events.slice(0, 4)); | |
| stack.addSpacer(); | |
| drawEventList(stack, events.slice(4, 8)); | |
| } | |
| if (config.widgetFamily === 'large') { | |
| var stack = widget.addStack(); | |
| stack.layoutHorizontally(); | |
| drawEventList(stack, events.slice(0, 8)); | |
| stack.addSpacer(); | |
| drawEventList(stack, events.slice(8, 16)); | |
| } | |
| if (config.widgetFamily === 'extraLarge') { | |
| var stack = widget.addStack(); | |
| stack.layoutHorizontally(); | |
| drawEventList(stack, events.slice(0, 8)); | |
| stack.addSpacer(); | |
| drawEventList(stack, events.slice(8, 16)); | |
| stack.addSpacer(); | |
| drawEventList(stack, events.slice(16, 24)); | |
| stack.addSpacer(); | |
| drawEventList(stack, events.slice(24, 32)); | |
| } | |
| } | |
| return widget; | |
| } | |
| function drawEventList(stack, events) { | |
| var eventStack = stack.addStack(); | |
| eventStack.layoutVertically(); | |
| for (const e of events) { | |
| drawProgressWidget(eventStack, e); | |
| // eventStack.addSpacer(1); | |
| } | |
| } | |
| function drawProgressWidget(stack, event) { | |
| var width = 500, height = 100; | |
| var mainTextColor = Color.dynamic(Color.black(), Color.white()); | |
| var mainTextFont = Font.boldRoundedSystemFont(height * 0.4); | |
| var subTextFont = Font.boldRoundedSystemFont(height * 0.2); | |
| // Drawing Canvas | |
| var canvas = new DrawContext(); | |
| canvas.size = new Size(width, height); | |
| canvas.opaque = false; | |
| canvas.respectScreenScale = true; | |
| drawText(canvas, event.name, new Point(0, 0), mainTextColor, mainTextFont); | |
| drawProgressBar(canvas, event.percentage, 0, height * 0.6, width * 0.4, height * 0.1); | |
| drawText(canvas, event.dueDate, new Point(width * 0.5, height * 0.5), mainTextColor, subTextFont); | |
| stack.addImage(canvas.getImage()); | |
| } | |
| function drawProgressBar(canvas, percentage, barLeft, barTop, barWidth, barHeight) { | |
| var roundSize = barHeight / 2; | |
| // Bar Container | |
| canvas.setFillColor(Color.dynamic(Color.darkGray(), Color.lightGray())); | |
| var bar = new Path(); | |
| bar.addRoundedRect( | |
| new Rect(barLeft, barTop, barWidth, barHeight), | |
| roundSize, roundSize); | |
| canvas.addPath(bar); | |
| canvas.fillPath(); | |
| // Progress Bar | |
| canvas.setFillColor(percentage > 1 ? Color.red() : Color.green()); | |
| var progress = new Path(); | |
| progress.addRoundedRect( | |
| new Rect(barLeft, barTop, barWidth * Math.min(1, percentage), barHeight), | |
| roundSize, roundSize | |
| ); | |
| canvas.addPath(progress); | |
| canvas.fillPath(); | |
| } | |
| function drawText(canvas, text, position, color, font) { | |
| canvas.setTextColor(color); | |
| canvas.setFont(font); | |
| canvas.drawText(text, position); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment