TF-3578 Calendar event show free busy status
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:jmap_dart_client/http/http_client.dart';
|
||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/response/response_object.dart';
|
||||
import 'package:jmap_dart_client/jmap/jmap_request.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/calendar/attendance/get_calendar_event_attendance_method.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/calendar/attendance/get_calendar_event_attendance_response.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/calendar/parse/calendar_event_parse_method.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/calendar/parse/calendar_event_parse_response.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/calendar/reply/calendar_event_accept_method.dart';
|
||||
@@ -23,8 +28,20 @@ class CalendarEventAPI {
|
||||
|
||||
Future<List<BlobCalendarEvent>> parse(AccountId accountId, Set<Id> blobIds) async {
|
||||
final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation());
|
||||
|
||||
// Parse
|
||||
final calendarEventParseMethod = CalendarEventParseMethod(accountId, blobIds);
|
||||
final calendarEventParseInvocation = requestBuilder.invocation(calendarEventParseMethod);
|
||||
|
||||
// Free/Busy query
|
||||
final calendarEventAttendanceGetMethod = GetCalendarEventAttendanceMethod(
|
||||
accountId,
|
||||
blobIds.toList(),
|
||||
);
|
||||
final calendarEventAttendanceGetInvocation = requestBuilder.invocation(
|
||||
calendarEventAttendanceGetMethod,
|
||||
);
|
||||
|
||||
final response = await (requestBuilder
|
||||
..usings(calendarEventParseMethod.requiredCapabilities))
|
||||
.build()
|
||||
@@ -33,11 +50,24 @@ class CalendarEventAPI {
|
||||
final calendarEventParseResponse = response.parse<CalendarEventParseResponse>(
|
||||
calendarEventParseInvocation.methodCallId,
|
||||
CalendarEventParseResponse.deserialize);
|
||||
final calendarEventAttendanceGetResponse = _parseCalendarEventAttendance(
|
||||
response,
|
||||
calendarEventAttendanceGetInvocation.methodCallId,
|
||||
);
|
||||
final calendarBlobIdStatusMap = Map.fromEntries(
|
||||
(calendarEventAttendanceGetResponse?.list ?? []).map(
|
||||
(calendarEventAttendance) => MapEntry(
|
||||
calendarEventAttendance.blobId,
|
||||
calendarEventAttendance.isFree,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (calendarEventParseResponse?.parsed?.isNotEmpty == true) {
|
||||
return calendarEventParseResponse!.parsed!.entries
|
||||
.map((entry) => BlobCalendarEvent(
|
||||
blobId: entry.key,
|
||||
isFree: calendarBlobIdStatusMap[entry.key] ?? true,
|
||||
calendarEventList: entry.value))
|
||||
.toList();
|
||||
} else if (calendarEventParseResponse?.notParsable?.isNotEmpty == true) {
|
||||
@@ -49,6 +79,20 @@ class CalendarEventAPI {
|
||||
}
|
||||
}
|
||||
|
||||
GetCalendarEventAttendanceResponse? _parseCalendarEventAttendance(
|
||||
ResponseObject response,
|
||||
MethodCallId methodCallId,
|
||||
) {
|
||||
try {
|
||||
return response.parse<GetCalendarEventAttendanceResponse>(
|
||||
methodCallId,
|
||||
GetCalendarEventAttendanceResponse.deserialize);
|
||||
} catch (e) {
|
||||
logError('CalendarEventAPI.parse free/busy query error: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<CalendarEventAcceptResponse> acceptEventInvitation(
|
||||
AccountId accountId,
|
||||
Set<Id> blobIds,
|
||||
|
||||
@@ -66,6 +66,7 @@ class CalendarEventRepositoryImpl extends CalendarEventRepository {
|
||||
calendarEventList: await Future.wait(blobCalendarEvent.calendarEventList.map((calendarEvent) {
|
||||
return _transformCalendarEventDescription(calendarEvent, transformConfiguration);
|
||||
})),
|
||||
isFree: blobCalendarEvent.isFree,
|
||||
);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
||||
|
||||
CalendarEvent? get calendarEvent => blobCalendarEvent.value?.calendarEventList.firstOrNull;
|
||||
Id? get _displayingEventBlobId => blobCalendarEvent.value?.blobId;
|
||||
bool get isCalendarEventFree => blobCalendarEvent.value?.isFree ?? true;
|
||||
|
||||
AccountId? get accountId => mailboxDashBoardController.accountId.value;
|
||||
|
||||
|
||||
@@ -371,6 +371,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
||||
presentationEmail: controller.currentEmail,
|
||||
onMailtoAttendeesAction: controller.handleMailToAttendees,
|
||||
openEmailAddressDetailAction: controller.openEmailAddressDialog,
|
||||
isFree: controller.isCalendarEventFree,
|
||||
)),
|
||||
if (_validateDisplayEventActionBanner(
|
||||
context: context,
|
||||
|
||||
@@ -5,9 +5,14 @@ import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
|
||||
class BlobCalendarEvent with EquatableMixin {
|
||||
final Id blobId;
|
||||
final List<CalendarEvent> calendarEventList;
|
||||
final bool isFree;
|
||||
|
||||
BlobCalendarEvent({required this.blobId, required this.calendarEventList});
|
||||
BlobCalendarEvent({
|
||||
required this.blobId,
|
||||
required this.calendarEventList,
|
||||
this.isFree = true,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [blobId, calendarEventList];
|
||||
List<Object?> get props => [blobId, calendarEventList, isFree];
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
|
||||
class EventTimeInformationWidgetStyles {
|
||||
static const double maxWidth = 100;
|
||||
static const double textSize = 16;
|
||||
static const double horizontalSpacing = 8;
|
||||
static const Color labelColor = AppColor.colorSubTitleEventActionText;
|
||||
static const Color valueColor = Colors.black;
|
||||
static const Color conflictColor = AppColor.warningColor;
|
||||
}
|
||||
+6
-1
@@ -32,6 +32,7 @@ class CalendarEventInformationWidget extends StatelessWidget {
|
||||
final PresentationEmail? presentationEmail;
|
||||
final OnMailtoAttendeesAction? onMailtoAttendeesAction;
|
||||
final OnOpenEmailAddressDetailAction? openEmailAddressDetailAction;
|
||||
final bool isFree;
|
||||
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
|
||||
@@ -40,6 +41,7 @@ class CalendarEventInformationWidget extends StatelessWidget {
|
||||
required this.calendarEvent,
|
||||
required this.onCalendarEventReplyActionClick,
|
||||
required this.calendarEventReplying,
|
||||
required this.isFree,
|
||||
this.onOpenNewTabAction,
|
||||
this.onOpenComposerAction,
|
||||
this.presentationEmail,
|
||||
@@ -250,7 +252,10 @@ class CalendarEventInformationWidget extends StatelessWidget {
|
||||
if (dateTimeEvent.isNotEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: CalendarEventInformationWidgetStyles.fieldTopPadding),
|
||||
child: EventTimeInformationWidget(timeEvent: dateTimeEvent),
|
||||
child: EventTimeInformationWidget(
|
||||
timeEvent: dateTimeEvent,
|
||||
isFree: isFree,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
|
||||
+25
-4
@@ -1,7 +1,10 @@
|
||||
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||
import 'package:core/presentation/utils/style_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/styles/event_time_information_widget_styles.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
@@ -9,17 +12,21 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
class EventTimeInformationWidget extends StatelessWidget {
|
||||
|
||||
final String timeEvent;
|
||||
final bool isFree;
|
||||
|
||||
const EventTimeInformationWidget({
|
||||
super.key,
|
||||
required this.timeEvent
|
||||
required this.timeEvent,
|
||||
required this.isFree,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
final imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: EventTimeInformationWidgetStyles.maxWidth,
|
||||
@@ -32,7 +39,7 @@ class EventTimeInformationWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(child: Text(
|
||||
Flexible(child: Text(
|
||||
timeEvent,
|
||||
overflow: responsiveUtils.isPortraitMobile(context) ? null : CommonTextStyle.defaultTextOverFlow,
|
||||
softWrap: responsiveUtils.isPortraitMobile(context) ? null : CommonTextStyle.defaultSoftWrap,
|
||||
@@ -42,7 +49,21 @@ class EventTimeInformationWidget extends StatelessWidget {
|
||||
fontWeight: FontWeight.w500,
|
||||
color: EventTimeInformationWidgetStyles.valueColor
|
||||
),
|
||||
))
|
||||
)),
|
||||
if (!isFree)
|
||||
...[
|
||||
const SizedBox(width: EventTimeInformationWidgetStyles.horizontalSpacing),
|
||||
Tooltip(
|
||||
message: AppLocalizations.of(context).youHaveAnotherEventAtThatSameTime,
|
||||
child: SvgPicture.asset(
|
||||
imagePaths.icError,
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.fill,
|
||||
colorFilter: EventTimeInformationWidgetStyles.conflictColor.asFilter(),
|
||||
),
|
||||
),
|
||||
]
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user