Skip to content
This repository was archived by the owner on Oct 7, 2023. It is now read-only.

Commit 06ac6b9

Browse files
authored
Merge pull request #13 from rudotriton/large-widget
2 parents 61eff86 + 3ad5220 commit 06ac6b9

File tree

12 files changed

+272
-130
lines changed

12 files changed

+272
-130
lines changed

README.md

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
# Scriptable Calendar Widget
2-
31
<p align="center" >
4-
<img width="500" alt="scriptable calendar" src ="./assets/widget.png">
2+
<img alt="scriptable calendar" src ="./assets/scriptable-calendar-widget.jpg">
53
</p>
64

7-
- [Scriptable Calendar Widget](#scriptable-calendar-widget)
8-
- [Setting Up](#setting-up)
9-
- [Settings](#settings)
10-
- [Small widgets](#small-widgets)
11-
- [Development](#development)
5+
- [Setting Up](#setting-up)
6+
- [Customization](#customization)
7+
- [Small Widgets](#small-widgets)
8+
- [Large Widgets](#large-widgets)
9+
- [Development](#development)
1210

1311
## Setting Up
1412

@@ -21,7 +19,7 @@
2119
- Set the `Script` to be the script you just created and `When Interacting` to `Run Script` which will then launch Calendar app when you tap on the widget.
2220
- Return to your home screen which should now hopefully show the Scriptable calendar widget.
2321

24-
## Settings
22+
## Customization
2523

2624
- `debug` - set to `true` to show the widget in Scriptable, `false` to open a
2725
calendar app.
@@ -40,8 +38,7 @@
4038
- `locale` - a Unicode locale identifier string, this would change the weekday letters to the specified language.
4139
- `textColor` - color of all the other text
4240
- `eventDateTimeOpacity` - opacity value for event times
43-
- `showEventsView` - to show the events view or not, this would be set through widget parameters in order to set it per widget basis. (check: [Small widgets](#small-widgets))
44-
- `showCalendarView` - to show the calendar view or not, also set through widget parameters.
41+
- `widgetType` - for small widgets it determines which side to show. This would be set through widget parameters in order to set it per widget basis, rather than setting here and having all small widgets be the same type. (check: [Small widgets](#small-widgets))
4542
- `showAllDayEvents` - would either show or hide all day events.
4643
- `showCalendarBullet` - would show a `` in front of the event name which matches the calendar color from which the event originates.
4744
- `startWeekOnSunday` - would start the week either on a Sunday or a Monday.
@@ -51,19 +48,19 @@
5148
- `showPrevMonth` - would show days from the previous month if they fit into the calendar view.
5249
- `showNextMonth` - would show days from the next month if they fit into the calendar view.
5350

54-
## Small widgets
55-
56-
<p align="center" >
57-
<img width="350" alt="scriptable calendar" src ="./assets/small-widgets.png">
58-
</p>
51+
## Small Widgets
5952

60-
The script also supports small widgets or a medium widget with just one part. In this case the widget parameter (long press on the widget -> edit widget -> parameter) should be set to something like:
53+
The script also supports small widgets in which case the widget parameter (long press on the widget -> edit widget -> parameter) should be set to something like:
6154

6255
- `{ "bg": "top-left.jpg", "view": "events" }`
6356
- `{ "bg": "top-right.jpg", "view": "cal" }`
6457

6558
Where `"events"` specifies the events view and `"cal"` the calendar view. (Setting the background is not necessary).
6659

60+
## Large Widgets
61+
62+
The script should detect on its own that it is running in a large widget and will adjust accordingly.
63+
6764
## Development
6865

6966
- `npm install` - install dev dependencies
565 KB
Loading

assets/small-widgets.png

-1.83 MB
Binary file not shown.

assets/widget.png

-1.15 MB
Binary file not shown.

calendar.js

Lines changed: 103 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// src/settings.ts
2-
var params = JSON.parse(args.widgetParameter) || { bg: "transparent.jpg" };
2+
var params = JSON.parse(args.widgetParameter) || {};
33
var settings = {
44
debug: false,
55
calendarApp: "calshow",
6-
backgroundImage: params.bg,
6+
backgroundImage: params.bg ? params.bg : "transparent.jpg",
77
widgetBackgroundColor: "#000000",
88
todayTextColor: "#000000",
99
markToday: true,
@@ -17,8 +17,7 @@ var settings = {
1717
locale: "en-US",
1818
textColor: "#ffffff",
1919
eventDateTimeOpacity: 0.7,
20-
showEventsView: params.view ? params.view === "events" : true,
21-
showCalendarView: params.view ? params.view === "cal" : true,
20+
widgetType: params.view ? params.view : "cal",
2221
showAllDayEvents: true,
2322
showCalendarBullet: true,
2423
startWeekOnSunday: false,
@@ -430,7 +429,7 @@ var getSuffix_default = getSuffix;
430429
function formatEvent(
431430
stack,
432431
event,
433-
{ opacity, textColor, showCalendarBullet, showCompleteTitle }
432+
{ eventDateTimeOpacity, textColor, showCalendarBullet, showCompleteTitle }
434433
) {
435434
const eventLine = stack.addStack();
436435
if (showCalendarBullet) {
@@ -460,18 +459,56 @@ function formatEvent(
460459
}
461460
addWidgetTextLine_default(time, stack, {
462461
textColor,
463-
opacity,
462+
opacity: eventDateTimeOpacity,
464463
font: Font.regularSystemFont(14),
465464
});
466465
}
467466
var formatEvent_default = formatEvent;
468467

469468
// src/buildEventsView.ts
470-
async function buildEventsView(date, stack, settings2) {
469+
async function buildEventsView(
470+
events,
471+
stack,
472+
settings2,
473+
{
474+
horizontalAlign = "left",
475+
verticalAlign = "center",
476+
eventLimit = 3,
477+
eventSpacer = 8,
478+
showMsg = true,
479+
} = {}
480+
) {
471481
const leftStack = stack.addStack();
472-
stack.addSpacer();
482+
if (horizontalAlign === "left") {
483+
stack.addSpacer();
484+
}
473485
leftStack.layoutVertically();
474-
leftStack.addSpacer();
486+
if (verticalAlign === "bottom" || verticalAlign === "center") {
487+
leftStack.addSpacer();
488+
}
489+
if (events.length !== 0) {
490+
const numEvents = events.length > eventLimit ? eventLimit : events.length;
491+
for (let i = 0; i < numEvents; i += 1) {
492+
formatEvent_default(leftStack, events[i], settings2);
493+
if (i < numEvents - 1) {
494+
leftStack.addSpacer(eventSpacer);
495+
}
496+
}
497+
} else if (showMsg) {
498+
addWidgetTextLine_default(`No more events.`, leftStack, {
499+
textColor: settings2.textColor,
500+
opacity: settings2.eventDateTimeOpacity,
501+
font: Font.regularSystemFont(15),
502+
});
503+
}
504+
if (verticalAlign === "top" || verticalAlign === "center") {
505+
leftStack.addSpacer();
506+
}
507+
}
508+
var buildEventsView_default = buildEventsView;
509+
510+
// src/getEvents.ts
511+
async function getEvents(date, settings2) {
475512
let events = [];
476513
if (settings2.showEventsOnlyForToday) {
477514
events = await CalendarEvent.today([]);
@@ -493,34 +530,74 @@ async function buildEventsView(date, stack, settings2) {
493530
futureEvents.push(event);
494531
}
495532
}
496-
if (futureEvents.length !== 0) {
497-
const numEvents = futureEvents.length > 3 ? 3 : futureEvents.length;
498-
for (let i = 0; i < numEvents; i += 1) {
499-
formatEvent_default(leftStack, futureEvents[i], settings2);
500-
if (i < numEvents - 1) {
501-
leftStack.addSpacer(8);
533+
return futureEvents;
534+
}
535+
var getEvents_default = getEvents;
536+
537+
// src/buildLargeWidget.ts
538+
async function buildLargeWidget(date, events, stack, settings2) {
539+
const leftSide = stack.addStack();
540+
stack.addSpacer();
541+
const rightSide = stack.addStack();
542+
leftSide.layoutVertically();
543+
rightSide.layoutVertically();
544+
rightSide.addSpacer();
545+
rightSide.centerAlignContent();
546+
const leftSideEvents = events.slice(0, 8);
547+
const rightSideEvents = events.slice(8, 12);
548+
await buildEventsView_default(leftSideEvents, leftSide, settings2, {
549+
eventLimit: 8,
550+
eventSpacer: 6,
551+
});
552+
await buildCalendarView_default(date, rightSide, settings2);
553+
rightSide.addSpacer();
554+
await buildEventsView_default(rightSideEvents, rightSide, settings2, {
555+
eventLimit: 4,
556+
eventSpacer: 6,
557+
verticalAlign: "top",
558+
showMsg: false,
559+
});
560+
}
561+
var buildLargeWidget_default = buildLargeWidget;
562+
563+
// src/buildWidget.ts
564+
async function buildWidget(settings2) {
565+
const widget = new ListWidget();
566+
widget.backgroundColor = new Color(settings2.widgetBackgroundColor, 1);
567+
setWidgetBackground_default(widget, settings2.backgroundImage);
568+
widget.setPadding(16, 16, 16, 16);
569+
const today = new Date();
570+
const globalStack = widget.addStack();
571+
const events = await getEvents_default(today, settings2);
572+
switch (config.widgetFamily) {
573+
case "small":
574+
if (settings2.widgetType === "events") {
575+
await buildEventsView_default(events, globalStack, settings2);
576+
} else {
577+
await buildCalendarView_default(today, globalStack, settings2);
502578
}
503-
}
504-
} else {
505-
addWidgetTextLine_default(`No more events.`, leftStack, {
506-
textColor: settings2.textColor,
507-
opacity: settings2.eventDateTimeOpacity,
508-
font: Font.regularSystemFont(15),
509-
});
579+
break;
580+
case "large":
581+
await buildLargeWidget_default(today, events, globalStack, settings2);
582+
break;
583+
default:
584+
await buildEventsView_default(events, globalStack, settings2);
585+
await buildCalendarView_default(today, globalStack, settings2);
586+
break;
510587
}
511-
leftStack.addSpacer();
588+
return widget;
512589
}
513-
var buildEventsView_default = buildEventsView;
590+
var buildWidget_default = buildWidget;
514591

515592
// src/index.ts
516593
async function main() {
517594
if (config.runsInWidget) {
518-
const widget = await createWidget();
595+
const widget = await buildWidget_default(settings_default);
519596
Script.setWidget(widget);
520597
Script.complete();
521598
} else if (settings_default.debug) {
522599
Script.complete();
523-
const widget = await createWidget();
600+
const widget = await buildWidget_default(settings_default);
524601
await widget.presentMedium();
525602
} else {
526603
const appleDate = new Date("2001/01/01");
@@ -532,20 +609,5 @@ async function main() {
532609
Script.complete();
533610
}
534611
}
535-
async function createWidget() {
536-
const widget = new ListWidget();
537-
widget.backgroundColor = new Color(settings_default.widgetBackgroundColor, 1);
538-
setWidgetBackground_default(widget, settings_default.backgroundImage);
539-
widget.setPadding(16, 16, 16, 16);
540-
const today = new Date();
541-
const globalStack = widget.addStack();
542-
if (settings_default.showEventsView) {
543-
await buildEventsView_default(today, globalStack, settings_default);
544-
}
545-
if (settings_default.showCalendarView) {
546-
await buildCalendarView_default(today, globalStack, settings_default);
547-
}
548-
return widget;
549-
}
550612

551613
await main();

src/buildEventsView.ts

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,65 +8,57 @@ import { Settings } from "./settings";
88
* @param {WidgetStack} stack - onto which the events view is built
99
*/
1010
async function buildEventsView(
11-
date: Date,
11+
events: CalendarEvent[],
1212
stack: WidgetStack,
13-
settings: Settings
13+
settings: Settings,
14+
{
15+
horizontalAlign = "left",
16+
verticalAlign = "center",
17+
eventLimit = 3,
18+
eventSpacer = 8,
19+
showMsg = true,
20+
}: {
21+
horizontalAlign?: string;
22+
verticalAlign?: string;
23+
eventLimit?: number;
24+
eventSpacer?: number;
25+
showMsg?: boolean;
26+
} = {}
1427
): Promise<void> {
1528
const leftStack = stack.addStack();
16-
// push event view to the left
17-
stack.addSpacer();
29+
// add, spacer to the right side, this pushes event view to the left
30+
if (horizontalAlign === "left") {
31+
stack.addSpacer();
32+
}
1833

1934
leftStack.layoutVertically();
2035
// center the whole left part of the widget
21-
leftStack.addSpacer();
22-
23-
let events: CalendarEvent[] = [];
24-
if (settings.showEventsOnlyForToday) {
25-
events = await CalendarEvent.today([]);
26-
} else {
27-
const dateLimit = new Date();
28-
dateLimit.setDate(dateLimit.getDate() + settings.nextNumOfDays);
29-
events = await CalendarEvent.between(date, dateLimit);
30-
}
31-
32-
const futureEvents: CalendarEvent[] = [];
33-
// if we show events for the whole week, then we need to filter allDay events
34-
// to not show past allDay events
35-
// if allDayEvent's start date is later than a day ago from now then show it
36-
// TODO clear up this logic
37-
for (const event of events) {
38-
if (
39-
(settings.showAllDayEvents &&
40-
event.isAllDay &&
41-
event.startDate.getTime() >
42-
new Date(new Date().setDate(new Date().getDate() - 1)).getTime()) ||
43-
(event.endDate.getTime() > date.getTime() &&
44-
!event.title.startsWith("Canceled:"))
45-
) {
46-
futureEvents.push(event);
47-
}
36+
if (verticalAlign === "bottom" || verticalAlign === "center") {
37+
leftStack.addSpacer();
4838
}
4939

5040
// if we have events today; else if we don't
51-
if (futureEvents.length !== 0) {
41+
if (events.length !== 0) {
5242
// show the next 3 events at most
53-
const numEvents = futureEvents.length > 3 ? 3 : futureEvents.length;
43+
const numEvents = events.length > eventLimit ? eventLimit : events.length;
5444
for (let i = 0; i < numEvents; i += 1) {
55-
formatEvent(leftStack, futureEvents[i], settings);
45+
formatEvent(leftStack, events[i], settings);
5646
// don't add a spacer after the last event
5747
if (i < numEvents - 1) {
58-
leftStack.addSpacer(8);
48+
leftStack.addSpacer(eventSpacer);
5949
}
6050
}
61-
} else {
51+
} else if (showMsg) {
6252
addWidgetTextLine(`No more events.`, leftStack, {
6353
textColor: settings.textColor,
6454
opacity: settings.eventDateTimeOpacity,
6555
font: Font.regularSystemFont(15),
6656
});
6757
}
68-
// for centering
69-
leftStack.addSpacer();
58+
// for centering, pushes up from the bottom
59+
if (verticalAlign === "top" || verticalAlign === "center") {
60+
leftStack.addSpacer();
61+
}
7062
}
7163

7264
export default buildEventsView;

0 commit comments

Comments
 (0)