diff --git a/lib/Controller/ViewController.php b/lib/Controller/ViewController.php
index b5653f1e22..8b095a834a 100644
--- a/lib/Controller/ViewController.php
+++ b/lib/Controller/ViewController.php
@@ -178,7 +178,7 @@ public function getCalendarDotSvg(string $color = "#0082c9"): FileDisplayRespons
if (preg_match('/^([0-9a-f]{3}|[0-9a-f]{6})$/i', $color)) {
$validColor = '#' . $color;
}
- $svg = '';
+ $svg = '';
$folderName = implode('_', [
'calendar',
$this->userId
@@ -188,9 +188,11 @@ public function getCalendarDotSvg(string $color = "#0082c9"): FileDisplayRespons
} catch (NotFoundException $e) {
$folder = $this->appData->newFolder($folderName);
}
- $file = $folder->newFile($color . '.svg', $svg);
+ $filename = $color . '.svg';
+ $file = $folder->fileExists($filename) ? $folder->getFile($filename) : $folder->newFile($filename, $svg);
$response = new FileDisplayResponse($file);
$response->cacheFor(24 * 3600); // 1 day
+ $response->setHeaders(['Content-Type' => 'image/svg+xml']);
return $response;
}
}
diff --git a/lib/Dashboard/CalendarWidget.php b/lib/Dashboard/CalendarWidget.php
index 662cf24f8a..ab71f8c13f 100644
--- a/lib/Dashboard/CalendarWidget.php
+++ b/lib/Dashboard/CalendarWidget.php
@@ -30,6 +30,7 @@
use DateTimeImmutable;
use OCA\Calendar\AppInfo\Application;
use OCA\Calendar\Service\JSDataService;
+use OCA\DAV\CalDAV\CalendarImpl;
use OCP\AppFramework\Services\IInitialState;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Calendar\IManager;
@@ -40,10 +41,17 @@
use OCP\Dashboard\Model\WidgetButton;
use OCP\Dashboard\Model\WidgetItem;
use OCP\Dashboard\Model\WidgetOptions;
+use OCP\IConfig;
use OCP\IDateTimeFormatter;
use OCP\IL10N;
use OCP\IURLGenerator;
+use OCP\IUserManager;
use OCP\Util;
+use Sabre\VObject\Component\VEvent;
+use Sabre\VObject\Component\VTimeZone;
+use Sabre\VObject\Parameter;
+use Sabre\VObject\Property\VCard\Date;
+use Sabre\Xml\Reader;
class CalendarWidget implements IAPIWidget, IButtonWidget, IIconWidget, IOptionWidget {
private IL10N $l10n;
@@ -53,6 +61,7 @@ class CalendarWidget implements IAPIWidget, IButtonWidget, IIconWidget, IOptionW
private IURLGenerator $urlGenerator;
private IManager $calendarManager;
private ITimeFactory $timeFactory;
+ private IConfig $config;
/**
* CalendarWidget constructor.
@@ -70,7 +79,8 @@ public function __construct(IL10N $l10n,
IDateTimeFormatter $dateTimeFormatter,
IURLGenerator $urlGenerator,
IManager $calendarManager,
- ITimeFactory $timeFactory) {
+ ITimeFactory $timeFactory,
+ IConfig $config) {
$this->l10n = $l10n;
$this->initialStateService = $initialStateService;
$this->dataService = $dataService;
@@ -78,6 +88,7 @@ public function __construct(IL10N $l10n,
$this->urlGenerator = $urlGenerator;
$this->calendarManager = $calendarManager;
$this->timeFactory = $timeFactory;
+ $this->config = $config;
}
/**
@@ -143,34 +154,96 @@ public function load(): void {
* @param int $limit Max 14 items is the default
*/
public function getItems(string $userId, ?string $since = null, int $limit = 7): array {
+ // This is hw JS does it:
+ // const start = dateFactory()
+ // const end = dateFactory()
+ // end.setDate(end.getDate() + 14)
+ // const startOfToday = moment(start).startOf('day').toDate()
+ // get all vevents in this time range
+ // if "show tasks" is enabled, get all todos in the time range
+ // sort events by time
+ // filter events by COMPLETED and CANCELLED
+ // filter out all events that are before the start of the day:
+ // decorate the items with url / task url, colour, etc
+
$calendars = $this->calendarManager->getCalendarsForPrincipal('principals/users/' . $userId);
$count = count($calendars);
if ($count === 0) {
return [];
}
- $dateTime = (new DateTimeImmutable())->setTimestamp($this->timeFactory->getTime());
- $inTwoWeeks = $dateTime->add(new DateInterval('P14D'));
- $options = [
- 'timerange' => [
- 'start' => $dateTime,
- 'end' => $inTwoWeeks,
- ]
- ];
+
$widgetItems = [];
foreach ($calendars as $calendar) {
- $searchResult = $calendar->search('', [], $options, $limit);
- foreach ($searchResult as $calendarEvent) {
- /** @var DateTimeImmutable $startDate */
- $startDate = $calendarEvent['objects'][0]['DTSTART'][0];
- $widget = new WidgetItem(
- $calendarEvent['objects'][0]['SUMMARY'][0] ?? 'New Event',
- $this->dateTimeFormatter->formatTimeSpan(DateTime::createFromImmutable($startDate)),
- $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('calendar.view.index', ['objectId' => $calendarEvent['uid']])),
- $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('calendar.view.getCalendarDotSvg', ['color' => $calendar->getDisplayColor() ?? '#0082c9'])), // default NC blue fallback
- (string) $startDate->getTimestamp(),
- );
- $widgetItems[] = $widget;
+ $timezone = null;
+ if($calendar instanceof CalendarImpl) {
+ $tz = $calendar->getCalendarTimezoneString() ?? 'UTC';
+ $timezone = new \DateTimeZone($tz);
+ }
+ // make sure to include all day events
+ $startTimeWithTimezoneMidnight = $this->timeFactory->getDateTime('today', $timezone);
+ $startTimeWithTimezoneNow = $this->timeFactory->getDateTime('now', $timezone);
+ $endDate = clone $startTimeWithTimezoneMidnight;
+ $endDate->modify('+15 days');
+ $options = [
+ 'timerange' => [
+ 'start' => $startTimeWithTimezoneMidnight,
+ 'end' => $endDate,
+ ],
+ 'types' => [
+ 'VEVENT'
+ ],
+ 'sort_asc' => [
+ 'firstoccurence'
+ ]
+ ];
+ if($this->config->getUserValue($userId, Application::APP_ID, 'showTasks') === 'yes') {
+ $options['types'][] = 'VTODO';
}
+ $searchResults = $calendar->search('', [], $options, $limit);
+ foreach ($searchResults as $calendarEvent) {
+ $dtstart = DateTime::createFromImmutable($calendarEvent['objects'][0]['DTSTART'][0]);
+ if($calendarEvent['type'] === 'VEVENT') {
+ if($calendarEvent['objects'][0]['STATUS'][0] === 'CANCELLED') {
+ continue;
+ }
+ $timestring = $this->createVeventString($calendarEvent);
+ if($timestring === null) {
+ continue;
+ }
+ $widgetItems[] = new WidgetItem(
+ $calendarEvent['objects'][0]['SUMMARY'][0] ?? 'Untitled Event',
+ $timestring,
+ $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('calendar.view.index', ['objectId' => $calendarEvent['uid']])),
+ $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('calendar.view.getCalendarDotSvg', ['color' => $calendar->getDisplayColor() ?? '#0082c9'])), // default NC blue fallback
+ (string) $dtstart->getTimestamp(),
+ );
+ }
+ }
+// if($this->config->getUserValue($userId, Application::APP_ID, 'showTasks') === 'yes') {
+// $vTodoOptions = [
+// 'types' => [
+// 'VTODO'
+// ],
+// 'sort_desc' => [
+// 'id'
+// ]
+// ];
+// $vTodoSearchResults = $calendar->search('', [], $vTodoOptions, $limit);
+// foreach($vTodoSearchResults as $vTodo) {
+// if($vTodo['objects'][0]['STATUS'][0] === 'COMPLETED') {
+// continue;
+// }
+// $timestring = $this->createVTodoString($vTodo);
+// $widget = new WidgetItem(
+// $vTodo['objects'][0]['SUMMARY'][0] ?? 'Untitled Task',
+// $timestring,
+// $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('calendar.view.index', ['objectId' => $calendarEvent['uid']])),
+// $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('calendar.view.getCalendarDotSvg', ['color' => $calendar->getDisplayColor() ?? '#0082c9'])), // default NC blue fallback
+// (string) $dtstart->getTimestamp(),
+// );
+// $widgetItems[] = $widget;
+// }
+// }
}
return $widgetItems;
}
@@ -196,4 +269,32 @@ public function getWidgetButtons(string $userId): array {
public function getWidgetOptions(): WidgetOptions {
return new WidgetOptions(true);
}
+
+ private function createVeventString(array $calendarEvent) {
+ $dtstart = DateTime::createFromImmutable($calendarEvent['objects'][0]['DTSTART'][0]);
+ if(isset($calendarEvent['objects'][0]['STATUS']) && $calendarEvent['objects'][0]['STATUS'][0] === 'CANCELLED') {
+ return null;
+ }
+ if (isset($calendarEvent['objects'][0]['DTEND'])) {
+ /** @var Property\ICalendar\DateTime $dtend */
+ $dtend = DateTime::createFromImmutable($calendarEvent['objects'][0]['DTEND'][0]);
+ } elseif(isset($calendarEvent['objects'][0]['DURATION'])) {
+ $dtend = clone $dtstart;
+ $dtend = $dtend->add(new DateInterval($calendarEvent['objects'][0]['DURATION'][0]));
+ } else {
+ $dtend = clone $dtstart;
+ }
+
+ // End is in the past, skipping
+ if($dtend->getTimestamp() < $this->timeFactory->getTime()) {
+ return null;
+ }
+
+ // all day (and longer) events
+ if($dtstart->diff($dtend)->days >= 1) {
+ return $this->dateTimeFormatter->formatDate($dtstart);
+ }
+
+ return $this->dateTimeFormatter->formatDateTime($dtstart, 'short') . ' - ' . $this->dateTimeFormatter->formatTime($dtend, 'short');
+ }
}
diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue
index b31c6da328..d79a07fc0d 100644
--- a/src/views/Dashboard.vue
+++ b/src/views/Dashboard.vue
@@ -34,16 +34,13 @@
+ :main-text="item.title ?? ''"
+ :sub-text="item.subtitle"
+ :target-url="item.link">
-
-
+
+
![]()
+
@@ -64,20 +61,18 @@