f7cloud_client/apps/calendar/lib/Dashboard/CalendarWidget.php
root 8b6a0139db f7cloud_client
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 22:59:26 +00:00

230 lines
5.8 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2020 F7cloud GmbH and F7cloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Calendar\Dashboard;
use DateInterval;
use DateTime;
use DateTimeImmutable;
use OCA\Calendar\AppInfo\Application;
use OCA\Calendar\Service\JSDataService;
use OCP\AppFramework\Services\IInitialState;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Calendar\IManager;
use OCP\Dashboard\IAPIWidget;
use OCP\Dashboard\IAPIWidgetV2;
use OCP\Dashboard\IButtonWidget;
use OCP\Dashboard\IIconWidget;
use OCP\Dashboard\IOptionWidget;
use OCP\Dashboard\IReloadableWidget;
use OCP\Dashboard\Model\WidgetButton;
use OCP\Dashboard\Model\WidgetItem;
use OCP\Dashboard\Model\WidgetItems;
use OCP\Dashboard\Model\WidgetOptions;
use OCP\IDateTimeFormatter;
use OCP\IL10N;
use OCP\IURLGenerator;
class CalendarWidget implements IAPIWidget, IAPIWidgetV2, IButtonWidget, IIconWidget, IOptionWidget, IReloadableWidget {
protected IL10N $l10n;
protected IInitialState $initialStateService;
protected JSDataService $dataService;
protected IDateTimeFormatter $dateTimeFormatter;
protected IURLGenerator $urlGenerator;
protected IManager $calendarManager;
protected ITimeFactory $timeFactory;
/**
* CalendarWidget constructor.
*/
public function __construct(IL10N $l10n,
IInitialState $initialStateService,
JSDataService $dataService,
IDateTimeFormatter $dateTimeFormatter,
IURLGenerator $urlGenerator,
IManager $calendarManager,
ITimeFactory $timeFactory) {
$this->l10n = $l10n;
$this->initialStateService = $initialStateService;
$this->dataService = $dataService;
$this->dateTimeFormatter = $dateTimeFormatter;
$this->urlGenerator = $urlGenerator;
$this->calendarManager = $calendarManager;
$this->timeFactory = $timeFactory;
}
/**
* @inheritDoc
*/
#[\Override]
public function getId(): string {
return Application::APP_ID;
}
/**
* @inheritDoc
*/
#[\Override]
public function getTitle(): string {
return $this->l10n->t('Upcoming events');
}
/**
* @inheritDoc
*/
#[\Override]
public function getOrder(): int {
return 2;
}
/**
* @inheritDoc
*/
#[\Override]
public function getIconClass(): string {
return 'app-icon-calendar';
}
/**
* @inheritDoc
*/
#[\Override]
public function getUrl(): ?string {
return null;
}
/**
* @inheritDoc
*/
#[\Override]
public function getIconUrl(): string {
return $this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->imagePath(Application::APP_ID, 'calendar-dark.svg')
);
}
/**
* @inheritDoc
*/
#[\Override]
public function load(): void {
// No assets need to be loaded anymore as the widget is rendered from the API
}
#[\Override]
public function getItems(string $userId, ?string $since = null, int $limit = 7): array {
$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) {
if (method_exists($calendar, 'isEnabled') && $calendar->isEnabled() === false) {
continue;
}
if ($calendar->isDeleted()) {
continue;
}
$searchResult = $calendar->search('', [], $options, $limit);
foreach ($searchResult as $calendarEvent) {
// Find first recurrence in the future
$recurrence = null;
foreach ($calendarEvent['objects'] as $object) {
/** @var DateTimeImmutable $startDate */
$startDate = $object['DTSTART'][0];
if ($startDate->getTimestamp() >= $dateTime->getTimestamp()) {
$recurrence = $object;
break;
}
}
if ($recurrence === null) {
continue;
}
$widget = new WidgetItem(
$recurrence['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;
}
}
usort($widgetItems, static function (WidgetItem $a, WidgetItem $b) {
return (int)$a->getSinceId() - (int)$b->getSinceId();
});
return $widgetItems;
}
/**
* @inheritDoc
*/
#[\Override]
public function getItemsV2(string $userId, ?string $since = null, int $limit = 7): WidgetItems {
$widgetItems = $this->getItems($userId, $since, $limit);
$halfEmptyContentMessage = '';
if (!empty($widgetItems)) {
$startOfTomorrow = $this->timeFactory->getDateTime('tomorrow')->getTimestamp();
if ($widgetItems[0]->getSinceId() >= $startOfTomorrow) {
$halfEmptyContentMessage = $this->l10n->t('No more events today');
}
}
return new WidgetItems(
$widgetItems,
empty($widgetItems) ? $this->l10n->t('No upcoming events') : '',
$halfEmptyContentMessage,
);
}
/**
* @inheritDoc
*/
#[\Override]
public function getWidgetButtons(string $userId): array {
return [
new WidgetButton(
WidgetButton::TYPE_MORE,
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->linkToRoute(Application::APP_ID . '.view.index')
),
$this->l10n->t('More events')
),
];
}
/**
* @inheritDoc
*/
#[\Override]
public function getWidgetOptions(): WidgetOptions {
return new WidgetOptions(true);
}
/**
* @inheritDoc
*/
#[\Override]
public function getReloadInterval(): int {
return 600;
}
}