Signed-off-by: dartcafe <github@dartcafe.de>
This commit is contained in:
dartcafe 2022-05-06 10:57:26 +02:00
Родитель 19bc05f945
Коммит 795d414edf
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: CCE73CEF3035D3C8
6 изменённых файлов: 90 добавлений и 34 удалений

Просмотреть файл

@ -25,6 +25,7 @@ namespace OCA\Polls\Controller;
use DateTime;
use DateInterval;
use DateTimeZone;
use OCP\IRequest;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
@ -142,16 +143,19 @@ class OptionController extends Controller {
* findCalendarEvents
* @NoAdminRequired
*/
public function findCalendarEvents(int $optionId): DataResponse {
return $this->response(function () use ($optionId) {
public function findCalendarEvents(int $optionId, string $tz): DataResponse {
return $this->response(function () use ($optionId, $tz) {
$option = $this->optionService->get($optionId);
$searchFrom = new DateTime();
$searchTo = new DateTime();
// Search calendar entries which end inside one hour before option start time
$searchFrom = $searchFrom->setTimestamp($option->getTimestamp())->sub(new DateInterval('PT1H'));
// Search calendar entries which start inside one hour after option end time
$searchTo = $searchTo->setTimestamp($option->getTimestamp() + $option->getDuration())->add(new DateInterval('PT1H'));
$events = $this->calendarService->getEvents($searchFrom, $searchTo);
$timezone = new DateTimeZone($tz);
$searchFrom = (new DateTime())->setTimeZone($timezone);
$searchTo = (new DateTime())->setTimeZone($timezone);
// Search calendar entries which end inside one hour before option start time and one hour after option end time
$searchFrom->setTimestamp($option->getTimestamp())->sub(new DateInterval('PT1H'));
$searchTo->setTimestamp($option->getTimestamp() + $option->getDuration())->add(new DateInterval('PT1H'));
$events = $this->calendarService->getEvents($searchFrom, $searchTo, $timezone);
return ['events' => $events];
});
}

Просмотреть файл

@ -25,6 +25,7 @@ namespace OCA\Polls\Model;
use DateTimeImmutable;
use DateInterval;
use DateTimeZone;
use \OCP\Calendar\ICalendar;
use RRule\RRule;
@ -52,27 +53,33 @@ class CalendarEvent implements \JsonSerializable {
/** @var array */
protected $event;
/** @var DateTimeImmutable */
protected $filterFrom;
/** @var DateTimeImmutable */
protected $filterTo;
/** @var ICalendar */
protected $calendar;
/** @var DateTimeImmutable */
protected $filterFrom;
/** @var DateTimeImmutable */
protected $filterTo;
/** @var DateTimeZone */
protected $timezone;
public function __construct(
array $iCal,
ICalendar $calendar,
DateTimeImmutable $filterFrom = null,
DateTimeImmutable $filterTo = null
DateTimeImmutable $filterTo = null,
DateTimeZone $timezone = null
) {
$this->iCal = $iCal;
$this->calendar = $calendar;
$this->event = $this->iCal['objects'][0];
$this->filterFrom = $filterFrom;
$this->filterTo = $filterTo;
$this->timezone = $timezone;
$this->event = $this->iCal['objects'][0];
$this->hasRRule = isset($this->event['RRULE']);
$this->fixAllDay();
$this->buildRRule();
$this->calculateOccurrences();
}
@ -202,6 +209,16 @@ class CalendarEvent implements \JsonSerializable {
return $this->occurrences;
}
private function fixAllDay(): void {
// force all day events to 00:00 in the user's timezone
if ($this->getType() === self::TYPE_DATE) {
$this->event['DTSTART'][0] = $this->event['DTSTART'][0]->setTimezone($this->timezone);
$this->event['DTEND'][0] = $this->event['DTEND'][0]->setTimezone($this->timezone);
$this->event['DTSTART'][0] = $this->event['DTSTART'][0]->setTime(0, 0);
$this->event['DTEND'][0] = $this->event['DTEND'][0]->setTime(0, 0);
}
}
private function buildRRule() : void {
if (!$this->getHasRRule()) {
return;

Просмотреть файл

@ -26,6 +26,7 @@ namespace OCA\Polls\Service;
use DateTime;
use DateTimeImmutable;
use DateTimeZone;
use OCP\Calendar\ICalendar;
use OCP\Calendar\IManager as CalendarManager;
use OCP\Util;
@ -97,7 +98,7 @@ class CalendarService {
*
* @psalm-return list<CalendarEvent>
*/
public function getEvents(DateTime $from, DateTime $to): array {
public function getEvents(DateTime $from, DateTime $to, DateTimeZone $timezone): array {
$from = DateTimeImmutable::createFromMutable($from);
$to = DateTimeImmutable::createFromMutable($to);
@ -127,7 +128,7 @@ class CalendarService {
continue;
}
$calendarEvent = new CalendarEvent($event, $calendar, $from, $to);
$calendarEvent = new CalendarEvent($event, $calendar, $from, $to, $timezone);
if ($calendarEvent->getOccurrences()) {
for ($index = 0; $index < count($calendarEvent->getOccurrences()); $index++) {
$calendarEvent->setOccurrence($index);

Просмотреть файл

@ -24,11 +24,14 @@
<div class="calendar-info"
:class="[conflictLevel, statusClass]"
:style="calendarStyle">
<div v-if="!event.allDay" class="calendar-info__time">
{{ formatDate(event.start) }} - {{ formatDate(event.end) }}
<div v-if="calendarEvent.allDay" class="calendar-info__time">
{{ dayStart }} {{ dayEnd }}
</div>
<div v-else class="calendar-info__time">
{{ formatDate(calendarEvent.start) }} - {{ formatDate(calendarEvent.end) }}
</div>
<div class="summay" :class="statusClass">
{{ event.summary }}
{{ calendarEvent.summary }}
</div>
</div>
</template>
@ -40,7 +43,7 @@ export default {
name: 'CalendarInfo',
props: {
event: {
calendarEvent: {
type: Object,
default: undefined,
},
@ -55,21 +58,35 @@ export default {
computed: {
calendarStyle() {
return {
backgroundColor: this.event.displayColor,
backgroundColor: this.calendarEvent.displayColor,
color: this.fontColor,
}
},
dayStart() {
return moment.unix(this.calendarEvent.start).format('ddd')
},
dayEnd() {
const dayEnd = moment.unix(this.calendarEvent.end - 1).format('ddd')
if (dayEnd === this.dayStart) {
return ''
}
return `- ${dayEnd}`
},
statusClass() {
return this.event.status.toLowerCase()
return this.calendarEvent.status.toLowerCase()
},
fontColor() {
if (this.event.displayColor === 'transparent') {
if (this.calendarEvent.displayColor === 'transparent') {
return 'var(--color-main-text)'
}
const hex = this.event.displayColor.replace(/#/, '')
const hex = this.calendarEvent.displayColor.replace(/#/, '')
const r = parseInt(hex.slice(0, 2), 16)
const g = parseInt(hex.slice(2, 4), 16)
const b = parseInt(hex.slice(4, 6), 16)
@ -84,15 +101,17 @@ export default {
},
conflictLevel() {
if (this.event.calendarKey === 0) {
if (this.calendarEvent.calendarKey === 0) {
return 'conflict-ignore'
}
if (this.event.start > this.option.timestamp + 3599) {
// No conflict, if calendarEvent starts after end of option
if (this.calendarEvent.start >= this.option.timestamp + this.option.duration) {
return 'conflict-no'
}
if (this.event.end - 1 < this.option.timestamp) {
// No conflict, if calendarEvent ends before option
if (this.calendarEvent.end <= this.option.timestamp) {
return 'conflict-no'
}

Просмотреть файл

@ -31,7 +31,7 @@
<div class="calendar-peek__grid">
<CalendarInfo v-for="eventItem in sortedEvents"
:key="eventItem.UID"
:event="eventItem"
:calendar-event="eventItem"
:option="option" />
</div>
</Popover>
@ -42,6 +42,7 @@
import { mapState } from 'vuex'
import orderBy from 'lodash/orderBy'
import { Popover } from '@nextcloud/vue'
import moment from '@nextcloud/moment'
import CalendarInfo from '../Calendar/CalendarInfo.vue'
import { showError } from '@nextcloud/dialogs'
@ -71,6 +72,16 @@ export default {
poll: (state) => state.poll,
}),
detectAllDay() {
const from = moment.unix(this.option.timestamp)
const to = moment.unix(this.option.timestamp + Math.max(0, this.option.duration))
const dayLongEvent = from.unix() === moment(from).startOf('day').unix() && to.unix() === moment(to).startOf('day').unix() && from.unix() !== to.unix()
return {
allDay: dayLongEvent,
type: dayLongEvent ? 'date' : 'dateTime',
}
},
sortedEvents() {
const sortedEvents = [...this.events]
sortedEvents.push(this.thisOption)
@ -85,14 +96,14 @@ export default {
calendarKey: 0,
calendarName: 'Polls',
displayColor: 'transparent',
allDay: '',
allDay: this.detectAllDay.allDay,
description: this.poll.description,
start: this.option.timestamp,
location: '',
end: this.option.timestamp + this.option.duration,
status: 'self',
summary: this.poll.title,
type: '',
type: this.detectAllDay.type,
}
},
},

Просмотреть файл

@ -302,7 +302,11 @@ const actions = {
const endPoint = `apps/polls/option/${payload.option.id}/events`
try {
return await axios.get(generateUrl(endPoint))
return await axios.get(generateUrl(endPoint), {
params: {
tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
},
})
} catch (e) {
return { events: [] }
}