diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 00000000..a6427fd2 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,4 @@ +{ + "flutter": "stable", + "flavors": {} +} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e001cdc0..175311fa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,7 +80,7 @@ jobs: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 with: - flutter-version: '3.13.9' + flutter-version: '3.27.1' channel: 'stable' - name: Install dependencies run: flutter pub get @@ -96,7 +96,7 @@ jobs: - name: Install Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.13.9' + flutter-version: '3.27.1' channel: 'stable' - name: Check Publish Warnings run: dart pub publish --dry-run diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d918d4b7..ad96db88 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 with: - flutter-version: "3.13.9" + flutter-version: "3.27.1" channel: "stable" - name: Install dependencies run: flutter pub get diff --git a/assets/svg/avatar-default.svg b/assets/svg/avatar-default.svg new file mode 100644 index 00000000..aeaca1f0 --- /dev/null +++ b/assets/svg/avatar-default.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/lib/blip_ds.dart b/lib/blip_ds.dart index f819e972..ffd0d289 100644 --- a/lib/blip_ds.dart +++ b/lib/blip_ds.dart @@ -1,4 +1,6 @@ -library blip_ds; +library; + +export 'package:scroll_to_index/scroll_to_index.dart' show AutoScrollController; export 'src/enums/ds_align.enum.dart' show DSAlign; export 'src/enums/ds_border_radius.enum.dart' show DSBorderRadius; @@ -58,6 +60,7 @@ export 'src/models/interactive_message/ds_interactive_message_video.model.dart' show DSInteractiveMessageVideo; export 'src/services/ds_auth.service.dart' show DSAuthService; export 'src/services/ds_bottom_sheet.service.dart' show DSBottomSheetService; +export 'src/services/ds_context.service.dart' show DSContextService; export 'src/services/ds_dialog.service.dart' show DSDialogService; export 'src/services/ds_file.service.dart' show DSFileService; export 'src/services/ds_localization.service.dart' show DSLocalizationService; @@ -67,6 +70,7 @@ export 'src/services/ds_toast.service.dart' show DSToastService; export 'src/themes/colors/ds_colors.theme.dart' show DSColors; export 'src/themes/colors/ds_dark_colors.theme.dart' show DSDarkColors; export 'src/themes/colors/ds_linear_gradient.theme.dart' show DSLinearGradient; +export 'src/themes/enums/ds_theme_type.enum.dart' show DSThemeType; export 'src/themes/icons/ds_icons.dart' show DSIcons; export 'src/themes/system_overlay/ds_system_overlay.style.dart' show DSSystemOverlayStyle; @@ -89,6 +93,7 @@ export 'src/themes/texts/styles/ds_headline_large_text_style.theme.dart' show DSHeadlineLargeTextStyle; export 'src/themes/texts/styles/ds_headline_small_text_style.theme.dart' show DSHeadlineSmallTextStyle; +export 'src/themes/texts/styles/ds_text_style.theme.dart' show DSTextStyle; export 'src/themes/texts/utils/ds_font_families.theme.dart' show DSFontFamilies; export 'src/themes/texts/utils/ds_font_weights.theme.dart' show DSFontWeights; export 'src/utils/ds_animate.util.dart' show DSAnimate; @@ -133,6 +138,8 @@ export 'src/widgets/chat/audio/ds_audio_message_bubble.widget.dart' export 'src/widgets/chat/audio/ds_audio_player.widget.dart' show DSAudioPlayer; export 'src/widgets/chat/calls/ds_end_calls_message_bubble.widget.dart' show DSEndCallsMessageBubble; +export 'src/widgets/chat/ds_active_campaign_message_bubble.widget.dart' + show DSActiveCampaignMessageBubble; export 'src/widgets/chat/ds_application_json_message_bubble.widget.dart' show DSApplicationJsonMessageBubble; export 'src/widgets/chat/ds_carrousel.widget.dart' show DSCarrousel; @@ -217,3 +224,5 @@ export 'src/widgets/utils/ds_group_card.widget.dart' show DSGroupCard; export 'src/widgets/utils/ds_header.widget.dart' show DSHeader; export 'src/widgets/utils/ds_progress_bar.widget.dart' show DSProgressBar; export 'src/widgets/utils/ds_user_avatar.widget.dart' show DSUserAvatar; +export 'src/widgets/utils/reply_content/ds_reply_preview.widget.dart' + show DSReplyPreview; diff --git a/lib/src/controllers/ds_video_player.controller.dart b/lib/src/controllers/ds_video_player.controller.dart index 578ddea5..405778e7 100644 --- a/lib/src/controllers/ds_video_player.controller.dart +++ b/lib/src/controllers/ds_video_player.controller.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; import 'package:video_player/video_player.dart'; import '../services/ds_auth.service.dart'; +import '../services/ds_navigation.service.dart'; import '../themes/colors/ds_colors.theme.dart'; import '../widgets/chat/video/ds_video_error.dialog.dart'; @@ -66,7 +67,7 @@ class DSVideoPlayerController extends GetxController { } Future _showErrorDialog() async { - Get.back(); + NavigationService.pop(); Get.delete(); await DSVideoErrorDialog.show( diff --git a/lib/src/enums/ds_delivery_report_status.enum.dart b/lib/src/enums/ds_delivery_report_status.enum.dart index 14713945..e975cfc7 100644 --- a/lib/src/enums/ds_delivery_report_status.enum.dart +++ b/lib/src/enums/ds_delivery_report_status.enum.dart @@ -7,5 +7,6 @@ enum DSDeliveryReportStatus { consumed, failed, sending, + dispatched, unknown, } diff --git a/lib/src/models/ds_active_message.model.dart b/lib/src/models/ds_active_message.model.dart new file mode 100644 index 00000000..6836d3b8 --- /dev/null +++ b/lib/src/models/ds_active_message.model.dart @@ -0,0 +1,33 @@ +import 'ds_active_message_template.model.dart'; +import 'ds_active_message_template_content.model.dart'; + +class DSActiveMessage { + DSActiveMessage({ + required this.type, + this.template, + this.templateContent, + }); + + final String type; + final DSActiveMessageTemplate? template; + final DSActiveMessageTemplateContent? templateContent; + + factory DSActiveMessage.fromJson(Map json) { + return DSActiveMessage( + type: json['type'], + template: json['template'] != null + ? DSActiveMessageTemplate.fromJson(json['template']) + : null, + templateContent: + DSActiveMessageTemplateContent.fromJson(json['templateContent']), + ); + } + + Map toJson() { + return { + 'type': type, + 'template': template, + 'templateContent': templateContent, + }; + } +} diff --git a/lib/src/models/ds_active_message_template.model.dart b/lib/src/models/ds_active_message_template.model.dart new file mode 100644 index 00000000..8c783924 --- /dev/null +++ b/lib/src/models/ds_active_message_template.model.dart @@ -0,0 +1,31 @@ +class DSActiveMessageTemplate { + const DSActiveMessageTemplate({ + this.name, + this.language, + this.components, + }); + + final String? name; + final Map? language; + final List>? components; + + factory DSActiveMessageTemplate.fromJson(Map json) { + return DSActiveMessageTemplate( + name: json['name'], + language: (json['language'] as Map?)?.map( + (key, value) => MapEntry(key, value), + ), + components: (json['components'] as List?) + ?.map((e) => e as Map) + .toList(), + ); + } + + Map toJson() { + return { + 'name': name, + 'language': language, + 'components': components, + }; + } +} diff --git a/lib/src/models/ds_active_message_template_content.model.dart b/lib/src/models/ds_active_message_template_content.model.dart new file mode 100644 index 00000000..940458aa --- /dev/null +++ b/lib/src/models/ds_active_message_template_content.model.dart @@ -0,0 +1,29 @@ +class DSActiveMessageTemplateContent { + const DSActiveMessageTemplateContent({ + this.name, + this.language, + this.components, + }); + + final String? name; + final String? language; + final List>? components; + + factory DSActiveMessageTemplateContent.fromJson(Map json) { + return DSActiveMessageTemplateContent( + name: json['name'], + language: json['language'], + components: (json['components'] as List?) + ?.map((e) => e as Map) + .toList(), + ); + } + + Map toJson() { + return { + 'name': name, + 'language': language, + 'components': components, + }; + } +} diff --git a/lib/src/models/ds_location.model.dart b/lib/src/models/ds_location.model.dart new file mode 100644 index 00000000..bdb6e16f --- /dev/null +++ b/lib/src/models/ds_location.model.dart @@ -0,0 +1,31 @@ +import '../extensions/ds_localization.extension.dart'; + +class DSLocation { + DSLocation({ + required this.text, + this.latitude, + this.longitude, + }); + + final double? latitude; + final double? longitude; + final String text; + + factory DSLocation.fromJson(Map json) { + return DSLocation( + latitude: double.tryParse(json['latitude']?.toString() ?? ''), + longitude: double.tryParse(json['longitude']?.toString() ?? ''), + text: (json['text']?.isNotEmpty ?? false) + ? json['text'] + : 'location.text'.translate(), + ); + } + + Map toJson() { + return { + 'latitude': latitude, + 'longitude': longitude, + 'text': text, + }; + } +} diff --git a/lib/src/models/ds_media_link.model.dart b/lib/src/models/ds_media_link.model.dart index 3fa551b6..7d19c313 100644 --- a/lib/src/models/ds_media_link.model.dart +++ b/lib/src/models/ds_media_link.model.dart @@ -6,6 +6,7 @@ class DSMediaLink { String? aspectRatio; int? size; String? authorizationRealm; + String? previewUri; DSMediaLink({ required this.uri, @@ -15,6 +16,7 @@ class DSMediaLink { this.aspectRatio, this.size, this.authorizationRealm, + this.previewUri, }); DSMediaLink.fromJson(Map json) @@ -24,5 +26,6 @@ class DSMediaLink { text = json['text'], aspectRatio = json['aspectRatio'], size = json['size'], - authorizationRealm = json['authorizationRealm']; + authorizationRealm = json['authorizationRealm'], + previewUri = json['previewUri']; } diff --git a/lib/src/models/ds_media_reply_content_props.model.dart b/lib/src/models/ds_media_reply_content_props.model.dart new file mode 100644 index 00000000..4f1683be --- /dev/null +++ b/lib/src/models/ds_media_reply_content_props.model.dart @@ -0,0 +1,19 @@ +import 'package:flutter/widgets.dart'; + +class DSMediaReplyContentProps { + String mediaTextTranslateKey; + IconData mediaIcon; + Widget trailing; + double size; + String title; + Widget? subtitle; + + DSMediaReplyContentProps({ + required this.mediaTextTranslateKey, + required this.mediaIcon, + this.title = '', + this.trailing = const SizedBox.shrink(), + this.size = 0.0, + this.subtitle, + }); +} diff --git a/lib/src/models/ds_message_item.model.dart b/lib/src/models/ds_message_item.model.dart index c727a50c..468f9bd4 100644 --- a/lib/src/models/ds_message_item.model.dart +++ b/lib/src/models/ds_message_item.model.dart @@ -33,6 +33,9 @@ class DSMessageItem { /// if the media message is uploading bool isUploading; + /// Message metadata + Map? metadata; + /// Creates a new Design System's [DSMessageItemModel] model DSMessageItem({ this.id, @@ -45,6 +48,7 @@ class DSMessageItem { this.customer, this.hideMessageDetail, this.isUploading = false, + this.metadata, }); factory DSMessageItem.fromJson(Map json) { @@ -68,6 +72,10 @@ class DSMessageItem { messageItem.hideMessageDetail = json['hideMessageDetail']; } + if (json.containsKey('metadata')) { + messageItem.metadata = json['metadata']; + } + return messageItem; } } diff --git a/lib/src/models/ds_reply_content.model.dart b/lib/src/models/ds_reply_content.model.dart index 8bb86101..b5157d73 100644 --- a/lib/src/models/ds_reply_content.model.dart +++ b/lib/src/models/ds_reply_content.model.dart @@ -17,4 +17,11 @@ class DSReplyContent { inReplyTo = DSReplyContentInReplyTo.fromJson( json['inReplyTo'], ); + + Map toJson() { + return { + 'replied': replied.toJson(), + 'inReplyTo': inReplyTo.toJson(), + }; + } } diff --git a/lib/src/models/ds_reply_content_in_reply_to.model.dart b/lib/src/models/ds_reply_content_in_reply_to.model.dart index 6373ea90..a761b91f 100644 --- a/lib/src/models/ds_reply_content_in_reply_to.model.dart +++ b/lib/src/models/ds_reply_content_in_reply_to.model.dart @@ -1,8 +1,8 @@ class DSReplyContentInReplyTo { - String id; - String type; + String? id; + String? type; dynamic value; - String direction; + String? direction; DSReplyContentInReplyTo({ required this.id, @@ -16,4 +16,26 @@ class DSReplyContentInReplyTo { type = json['type'] ?? '', value = json['value'] ?? '', direction = json['direction'] ?? ''; + + Map toJson() { + final Map data = {}; + + if (id != null) { + data['id'] = id; + } + + if (type != null) { + data['type'] = type; + } + + if (value != null) { + data['value'] = value; + } + + if (direction != null) { + data['direction'] = direction; + } + + return data; + } } diff --git a/lib/src/models/ds_reply_content_replied.model.dart b/lib/src/models/ds_reply_content_replied.model.dart index 6b2d2bcf..d5d43976 100644 --- a/lib/src/models/ds_reply_content_replied.model.dart +++ b/lib/src/models/ds_reply_content_replied.model.dart @@ -10,4 +10,18 @@ class DSReplyContentReplied { DSReplyContentReplied.fromJson(Map json) : type = json['type'], value = json['value']; + + Map toJson() { + final Map data = {}; + + if (type.isNotEmpty) { + data['type'] = type; + } + + if (value != null) { + data['value'] = value; + } + + return data; + } } diff --git a/lib/src/services/ds_bottom_sheet.service.dart b/lib/src/services/ds_bottom_sheet.service.dart index cd709cec..d0823c0e 100644 --- a/lib/src/services/ds_bottom_sheet.service.dart +++ b/lib/src/services/ds_bottom_sheet.service.dart @@ -125,8 +125,8 @@ class DSBottomSheetService { backgroundColor: Colors.transparent, isScrollControlled: true, context: context, - builder: (_) => WillPopScope( - onWillPop: () async => false, + builder: (_) => PopScope( + canPop: false, child: _buildBottomSheet( hideGrabber: true, ), diff --git a/lib/src/services/ds_context.service.dart b/lib/src/services/ds_context.service.dart new file mode 100644 index 00000000..90ab8fb5 --- /dev/null +++ b/lib/src/services/ds_context.service.dart @@ -0,0 +1,18 @@ +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; + +abstract class DSContextService { + static BuildContext? _context = Get.context; + static BuildContext? _overlayContext = Get.overlayContext; + + static init( + final BuildContext context, [ + final BuildContext? overlayContext, + ]) { + _context = context; + _overlayContext = overlayContext; + } + + static BuildContext? get context => _context; + static BuildContext? get overlayContext => _overlayContext ?? _context; +} diff --git a/lib/src/services/ds_dialog.service.dart b/lib/src/services/ds_dialog.service.dart index 151edc94..f7754f14 100644 --- a/lib/src/services/ds_dialog.service.dart +++ b/lib/src/services/ds_dialog.service.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:get/get.dart'; import '../enums/ds_dialog_type.enum.dart'; import '../themes/colors/ds_colors.theme.dart'; @@ -8,6 +7,7 @@ import '../themes/icons/ds_icons.dart'; import '../themes/system_overlay/ds_system_overlay.style.dart'; import '../widgets/texts/ds_body_text.widget.dart'; import '../widgets/texts/ds_headline_small_text.widget.dart'; +import 'ds_context.service.dart'; /// A Design System's [Dialog] used to display a dialog box. class DSDialogService { @@ -18,7 +18,7 @@ class DSDialogService { this.primaryButton, this.secondaryButton, final BuildContext? context, - }) : context = context ?? Get.overlayContext ?? Get.context!; + }) : context = context ?? DSContextService.overlayContext!; final String title; final String text; @@ -68,8 +68,8 @@ class DSDialogService { Widget _buildDialog(final DSDialogType type) { return AnnotatedRegion( value: DSSystemOverlayStyle.light, - child: WillPopScope( - onWillPop: () async => false, + child: PopScope( + canPop: false, child: Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15.0), @@ -81,7 +81,9 @@ class DSDialogService { borderRadius: const BorderRadius.all(Radius.circular(15.0)), boxShadow: [ BoxShadow( - color: DSColors.neutralDarkEclipse.withOpacity(0.4), + color: DSColors.neutralDarkEclipse.withValues( + alpha: 0.4, + ), blurRadius: 15.0, offset: const Offset(0.0, 3.0), ), diff --git a/lib/src/services/ds_navigation.service.dart b/lib/src/services/ds_navigation.service.dart new file mode 100644 index 00000000..49375afc --- /dev/null +++ b/lib/src/services/ds_navigation.service.dart @@ -0,0 +1,14 @@ +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; + +import 'ds_context.service.dart'; + +abstract class NavigationService { + static void pop([T? result]) { + try { + Get.back(result: result); + } catch (e) { + Navigator.of(DSContextService.context!).pop(result); + } + } +} diff --git a/lib/src/services/ds_toast.service.dart b/lib/src/services/ds_toast.service.dart index 1f5eecc1..fdc88a7d 100644 --- a/lib/src/services/ds_toast.service.dart +++ b/lib/src/services/ds_toast.service.dart @@ -5,6 +5,7 @@ import '../enums/ds_toast_type.enum.dart'; import '../models/ds_toast_props.model.dart'; import '../utils/ds_utils.util.dart'; import '../widgets/toast/ds_toast.widget.dart'; +import 'ds_context.service.dart'; /// A Design System's [DSToastService] used to display a toast. abstract class DSToastService { @@ -33,7 +34,7 @@ abstract class DSToastService { _controller = ScrollController(); _overlayEntry = _createOverlayEntry(); - Overlay.of(Get.overlayContext!).insert(_overlayEntry!); + Overlay.of(DSContextService.overlayContext!).insert(_overlayEntry!); } } diff --git a/lib/src/themes/colors/ds_colors.theme.dart b/lib/src/themes/colors/ds_colors.theme.dart index 257f8ac0..a19b2e79 100644 --- a/lib/src/themes/colors/ds_colors.theme.dart +++ b/lib/src/themes/colors/ds_colors.theme.dart @@ -51,6 +51,7 @@ abstract class DSColors { static const Color success = Color(0xFF84EBBC); static const Color error = Color(0xFFF99F9F); static const Color surface1 = Color(0xFFF6F6F6); + static const Color surface2 = Color(0xFFE0E0E0); static const Color surface3 = Color(0xFFC7C7C7); static const Color contentDefault = Color(0xFF454545); static const Color contentGhost = Color(0xFF949494); @@ -59,6 +60,8 @@ abstract class DSColors { static const Color disabledBg = Color(0xFFE8F2FF); static const Color contentDisable = Color(0xFF636363); static const Color border1 = Color(0xFFC9C9C9); + static const Color border2 = Color(0xFFE0E0E0); + static const Color border3 = Color(0xFFEDEDED); static Gradient gradientOcean = DSLinearGradient( colors: const [ diff --git a/lib/src/themes/enums/ds_theme_type.enum.dart b/lib/src/themes/enums/ds_theme_type.enum.dart new file mode 100644 index 00000000..96e84159 --- /dev/null +++ b/lib/src/themes/enums/ds_theme_type.enum.dart @@ -0,0 +1,4 @@ +enum DSThemeType { + dark, + light, +} diff --git a/lib/src/themes/texts/ds_text_selection_theme.theme.dart b/lib/src/themes/texts/ds_text_selection_theme.theme.dart index 4c02bfe8..b6331bb1 100644 --- a/lib/src/themes/texts/ds_text_selection_theme.theme.dart +++ b/lib/src/themes/texts/ds_text_selection_theme.theme.dart @@ -5,7 +5,9 @@ import '../colors/ds_colors.theme.dart'; class DSTextSelectionThemeData extends TextSelectionThemeData { DSTextSelectionThemeData() : super( - selectionColor: DSColors.primaryMain.withOpacity(0.5), + selectionColor: DSColors.primaryMain.withValues( + alpha: 0.5, + ), selectionHandleColor: DSColors.primaryDark, ); } diff --git a/lib/src/widgets/animations/ds_reply_swipe.widget.dart b/lib/src/widgets/animations/ds_reply_swipe.widget.dart new file mode 100644 index 00000000..02baa6a0 --- /dev/null +++ b/lib/src/widgets/animations/ds_reply_swipe.widget.dart @@ -0,0 +1,105 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../../models/ds_message_item.model.dart'; +import '../../themes/colors/ds_colors.theme.dart'; +import '../../utils/ds_utils.util.dart'; + +class DSReplySwipe extends StatefulWidget { + const DSReplySwipe({ + super.key, + required this.child, + required this.message, + this.onReply, + }); + + final DSMessageItem message; + final Widget child; + final void Function(DSMessageItem)? onReply; + + @override + State createState() => _DSReplySwipeState(); +} + +class _DSReplySwipeState extends State { + final progress = ValueNotifier(0.0); + + bool endReached = false; + + @override + void dispose() { + progress.dispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Dismissible( + key: widget.key ?? UniqueKey(), + onUpdate: (details) { + progress.value = details.progress; + }, + direction: widget.onReply != null + ? DismissDirection.startToEnd + : DismissDirection.none, + dismissThresholds: { + DismissDirection.startToEnd: double.infinity, + }, + confirmDismiss: (_) async { + return false; + }, + background: ValueListenableBuilder( + valueListenable: progress, + builder: (context, swipeProgress, _) { + final paddingProgress = clampDouble(swipeProgress * 3.5, 0, 1); + final opacityProgress = clampDouble(swipeProgress * 2.5, 0, 1); + + if (!endReached && paddingProgress == 1) { + endReached = true; + + HapticFeedback.lightImpact(); + + widget.onReply?.call(widget.message); + } else if (paddingProgress <= .8) { + endReached = false; + } + + return AnimatedSize( + duration: DSUtils.defaultAnimationDuration, + child: AnimatedOpacity( + duration: DSUtils.defaultAnimationDuration, + opacity: opacityProgress, + child: Row( + children: [ + Padding( + padding: EdgeInsets.lerp( + EdgeInsets.zero, + EdgeInsets.symmetric(horizontal: 40.0), + paddingProgress, + )!, + child: Container( + padding: const EdgeInsets.all(4.0), + decoration: BoxDecoration( + color: DSColors.contentDisable, + shape: BoxShape.circle, + // borderRadius: BorderRadius.circular(8.0), + ), + child: Icon( + Icons.reply, + color: DSColors.neutralLightSnow, + ), + ), + ), + ], + ), + ), + ); + }, + ), + child: widget.child, + ); + } +} diff --git a/lib/src/widgets/animations/ds_spinner_loading.widget.dart b/lib/src/widgets/animations/ds_spinner_loading.widget.dart index 97323f6c..e6f2eb58 100644 --- a/lib/src/widgets/animations/ds_spinner_loading.widget.dart +++ b/lib/src/widgets/animations/ds_spinner_loading.widget.dart @@ -66,7 +66,9 @@ class DSSpinnerLoadingState extends State color: Colors.transparent, border: Border.all( width: widget.lineWidth, - color: DSColors.neutralDarkEclipse.withOpacity(0.32), + color: DSColors.neutralDarkEclipse.withValues( + alpha: 0.32, + ), style: BorderStyle.solid, ), ), diff --git a/lib/src/widgets/buttons/ds_send_button.widget.dart b/lib/src/widgets/buttons/ds_send_button.widget.dart index 6ddb638f..2c22544d 100644 --- a/lib/src/widgets/buttons/ds_send_button.widget.dart +++ b/lib/src/widgets/buttons/ds_send_button.widget.dart @@ -16,6 +16,7 @@ class DSSendButton extends DSButton { }) : super( shape: DSButtonShape.rounded, leadingIcon: const Icon( + color: DSColors.neutralLightSnow, DSIcons.send_solid, ), backgroundColor: isEnabled ? backgroundColor : DSColors.disabledBg, diff --git a/lib/src/widgets/chat/audio/ds_audio_message_bubble.widget.dart b/lib/src/widgets/chat/audio/ds_audio_message_bubble.widget.dart index 70f8b8e0..b62ba11e 100644 --- a/lib/src/widgets/chat/audio/ds_audio_message_bubble.widget.dart +++ b/lib/src/widgets/chat/audio/ds_audio_message_bubble.widget.dart @@ -16,6 +16,7 @@ class DSAudioMessageBubble extends StatelessWidget { final String? uniqueId; final bool shouldAuthenticate; final DSReplyContent? replyContent; + final bool simpleStyle; final void Function(String)? onTapReply; DSAudioMessageBubble({ @@ -26,6 +27,7 @@ class DSAudioMessageBubble extends StatelessWidget { this.replyContent, this.borderRadius = const [DSBorderRadius.all], this.shouldAuthenticate = false, + this.simpleStyle = false, final DSMessageBubbleStyle? style, this.onTapReply, }) : style = style ?? DSMessageBubbleStyle(); @@ -42,6 +44,7 @@ class DSAudioMessageBubble extends StatelessWidget { replyContent: replyContent, style: style, padding: EdgeInsets.zero, + simpleStyle: simpleStyle, child: Padding( padding: const EdgeInsets.fromLTRB(4.0, 8.0, 8.0, 8.0), child: DSAudioPlayer( diff --git a/lib/src/widgets/chat/ds_active_campaign_message_bubble.widget.dart b/lib/src/widgets/chat/ds_active_campaign_message_bubble.widget.dart new file mode 100644 index 00000000..747d42d9 --- /dev/null +++ b/lib/src/widgets/chat/ds_active_campaign_message_bubble.widget.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; + +import '../../enums/ds_align.enum.dart'; +import '../../enums/ds_border_radius.enum.dart'; +import '../../extensions/ds_localization.extension.dart'; +import '../../models/ds_message_bubble_style.model.dart'; +import '../../models/ds_reply_content.model.dart'; +import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/icons/ds_icons.dart'; +import '../texts/ds_body_text.widget.dart'; +import '../texts/ds_headline_small_text.widget.dart'; +import 'ds_message_bubble.widget.dart'; + +class DSActiveCampaignMessageBubble extends StatelessWidget { + DSActiveCampaignMessageBubble({ + super.key, + required this.align, + this.name, + this.text, + this.replyContent, + this.overflow = TextOverflow.visible, + this.borderRadius = const [DSBorderRadius.all], + this.simpleStyle = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final DSAlign align; + final DSReplyContent? replyContent; + final String? name; + final String? text; + final TextOverflow overflow; + final List borderRadius; + final DSMessageBubbleStyle style; + final bool simpleStyle; + + @override + Widget build(BuildContext context) { + final color = style.isLightBubbleBackground(align) + ? DSColors.neutralDarkCity + : DSColors.neutralLightSnow; + + return DSMessageBubble( + borderRadius: borderRadius, + align: align, + style: style, + replyContent: replyContent, + simpleStyle: simpleStyle, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (name?.isNotEmpty ?? false) + Padding( + padding: const EdgeInsets.only( + bottom: 8.0, + ), + child: Row( + children: [ + Icon( + DSIcons.megaphone_outline, + color: style.isLightBubbleBackground(align) + ? DSColors.neutralDarkCity + : DSColors.neutralLightSnow, + ), + const SizedBox(width: 8.0), + Flexible( + child: DSHeadlineSmallText( + name!, + color: color, + overflow: overflow, + ), + ), + ], + ), + ), + Flexible( + child: DSBodyText( + text?.replaceAll(r"\n", '\n').trim() ?? + 'unsupported-content.text'.translate(), + color: color, + overflow: overflow, + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/widgets/chat/ds_application_json_message_bubble.widget.dart b/lib/src/widgets/chat/ds_application_json_message_bubble.widget.dart index 4c20fcfe..c80593c7 100644 --- a/lib/src/widgets/chat/ds_application_json_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_application_json_message_bubble.widget.dart @@ -8,6 +8,7 @@ import '../../models/ds_message_bubble_style.model.dart'; import '../../models/interactive_message/ds_interactive_message.model.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; +import 'ds_active_campaign_message_bubble.widget.dart'; import 'ds_interactive_button_message_bubble.widget.dart'; import 'ds_interactive_list_message_bubble.widget.dart'; import 'ds_interactive_voice_call_message_bubble.widget.dart'; @@ -21,6 +22,7 @@ class DSApplicationJsonMessageBubble extends StatelessWidget { this.borderRadius = const [DSBorderRadius.all], this.status, this.avatarConfig = const DSMessageBubbleAvatarConfig(), + this.simpleStyle = false, DSMessageBubbleStyle? style, this.onTapReply, }) : style = style ?? DSMessageBubbleStyle(), @@ -32,6 +34,7 @@ class DSApplicationJsonMessageBubble extends StatelessWidget { final DSDeliveryReportStatus? status; final DSMessageBubbleStyle style; final DSMessageBubbleAvatarConfig avatarConfig; + final bool simpleStyle; final Map content; final Map interactive; @@ -45,23 +48,41 @@ class DSApplicationJsonMessageBubble extends StatelessWidget { _ => _buildUnsupportedContent(), }; - Widget _buildTemplate() => Opacity( - opacity: status == DSDeliveryReportStatus.failed ? .3 : 1, - child: DSUnsupportedContentMessageBubble( - align: align, - borderRadius: borderRadius, - style: style, - overflow: TextOverflow.visible, - text: template['name'], - leftWidget: Icon( - DSIcons.megaphone_outline, - color: style.isLightBubbleBackground(align) - ? DSColors.neutralDarkCity - : DSColors.neutralLightSnow, - size: 20.0, - ), + Widget _buildTemplate() { + Widget child; + try { + final templateTextContent = + content['templateContent']['components'][0]['text']; + + child = DSActiveCampaignMessageBubble( + name: simpleStyle ? '' : template['name'], + text: templateTextContent.toString().replaceAll(r"\n", '\n').trim(), + align: align, + borderRadius: borderRadius, + style: style, + ); + } catch (_) { + child = DSUnsupportedContentMessageBubble( + align: align, + borderRadius: borderRadius, + style: style, + overflow: TextOverflow.visible, + text: template['name'], + leftWidget: Icon( + DSIcons.megaphone_outline, + color: style.isLightBubbleBackground(align) + ? DSColors.neutralDarkCity + : DSColors.neutralLightSnow, + size: 20.0, ), ); + } + + return Opacity( + opacity: status == DSDeliveryReportStatus.failed ? .3 : 1, + child: child, + ); + } Widget _buildInteractive() { final content = DSInteractiveMessage.fromJson(interactive); diff --git a/lib/src/widgets/chat/ds_contact_message_bubble.widget.dart b/lib/src/widgets/chat/ds_contact_message_bubble.widget.dart index abebb950..d58f3ea1 100644 --- a/lib/src/widgets/chat/ds_contact_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_contact_message_bubble.widget.dart @@ -19,6 +19,7 @@ class DSContactMessageBubble extends StatelessWidget { final DSAlign align; final List borderRadius; final DSMessageBubbleStyle style; + final bool simpleStyle; DSContactMessageBubble({ super.key, @@ -29,6 +30,7 @@ class DSContactMessageBubble extends StatelessWidget { required this.align, this.replyContent, this.borderRadius = const [DSBorderRadius.all], + this.simpleStyle = false, DSMessageBubbleStyle? style, }) : style = style ?? DSMessageBubbleStyle(); @@ -41,6 +43,7 @@ class DSContactMessageBubble extends StatelessWidget { shouldUseDefaultSize: true, style: style, replyContent: replyContent, + simpleStyle: simpleStyle, child: _buildContactCard(), ); } diff --git a/lib/src/widgets/chat/ds_delivery_report_icon.widget.dart b/lib/src/widgets/chat/ds_delivery_report_icon.widget.dart index 9f216776..420a828b 100644 --- a/lib/src/widgets/chat/ds_delivery_report_icon.widget.dart +++ b/lib/src/widgets/chat/ds_delivery_report_icon.widget.dart @@ -4,6 +4,7 @@ import 'package:flutter_svg/svg.dart'; import '../../enums/ds_delivery_report_status.enum.dart'; import '../../extensions/ds_localization.extension.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/enums/ds_theme_type.enum.dart'; import '../../themes/icons/ds_icons.dart'; import '../../utils/ds_utils.util.dart'; import '../texts/ds_caption_small_text.widget.dart'; @@ -11,11 +12,13 @@ import '../texts/ds_caption_small_text.widget.dart'; /// A Design System widget used to display a delivery report status icon. class DSDeliveryReportIcon extends StatelessWidget { final DSDeliveryReportStatus deliveryStatus; + final DSThemeType theme; /// Creates a new Design System's [DSDeliveryReportIcon] const DSDeliveryReportIcon({ super.key, required this.deliveryStatus, + this.theme = DSThemeType.dark, }); @override @@ -27,10 +30,13 @@ class DSDeliveryReportIcon extends StatelessWidget { const String path = 'assets/images'; switch (deliveryStatus) { + case DSDeliveryReportStatus.dispatched: case DSDeliveryReportStatus.accepted: return _getIcon( '$path/check.svg', - DSColors.neutralMediumElephant, + theme == DSThemeType.dark + ? DSColors.neutralMediumElephant + : DSColors.neutralLightSnow, ); case DSDeliveryReportStatus.failed: @@ -40,16 +46,20 @@ class DSDeliveryReportIcon extends StatelessWidget { ); case DSDeliveryReportStatus.sending: - return const Icon( + return Icon( DSIcons.clock_outline, size: 16, - color: DSColors.contentDefault, + color: theme == DSThemeType.dark + ? DSColors.contentDefault + : DSColors.neutralLightSnow, ); case DSDeliveryReportStatus.received: return _getIcon( '$path/check_double.svg', - DSColors.neutralMediumElephant, + theme == DSThemeType.dark + ? DSColors.neutralMediumElephant + : DSColors.neutralLightSnow, ); case DSDeliveryReportStatus.consumed: @@ -74,10 +84,12 @@ class DSDeliveryReportIcon extends StatelessWidget { ); default: - return const Icon( + return Icon( DSIcons.clock_outline, size: 16, - color: DSColors.contentDefault, + color: theme == DSThemeType.dark + ? DSColors.contentDefault + : DSColors.neutralLightSnow, ); } } diff --git a/lib/src/widgets/chat/ds_file_message_bubble.widget.dart b/lib/src/widgets/chat/ds_file_message_bubble.widget.dart index 8b4f40ef..f8189782 100644 --- a/lib/src/widgets/chat/ds_file_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_file_message_bubble.widget.dart @@ -28,6 +28,7 @@ class DSFileMessageBubble extends StatelessWidget { final bool shouldAuthenticate; final bool isUploading; final DSReplyContent? replyContent; + final bool simpleStyle; /// Creates a Design System's [DSMessageBubble] used on files other than image, audio, or video DSFileMessageBubble({ @@ -42,6 +43,7 @@ class DSFileMessageBubble extends StatelessWidget { DSMessageBubbleStyle? style, this.isUploading = false, this.replyContent, + this.simpleStyle = false, }) : style = style ?? DSMessageBubbleStyle(), controller = DSFileMessageBubbleController(); @@ -63,6 +65,7 @@ class DSFileMessageBubble extends StatelessWidget { padding: EdgeInsets.zero, align: align, style: style, + simpleStyle: simpleStyle, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/src/widgets/chat/ds_image_message_bubble.widget.dart b/lib/src/widgets/chat/ds_image_message_bubble.widget.dart index 9901e318..e209e8e7 100644 --- a/lib/src/widgets/chat/ds_image_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_image_message_bubble.widget.dart @@ -36,6 +36,7 @@ class DSImageMessageBubble extends StatefulWidget { this.mediaType, this.isUploading = false, this.replyContent, + this.simpleStyle = false, this.onTapReply, }) : style = style ?? DSMessageBubbleStyle(); @@ -56,6 +57,7 @@ class DSImageMessageBubble extends StatefulWidget { final String? mediaType; final bool isUploading; final DSReplyContent? replyContent; + final bool simpleStyle; final void Function(String)? onTapReply; @override @@ -95,6 +97,7 @@ class _DSImageMessageBubbleState extends State padding: EdgeInsets.zero, hasSpacer: widget.hasSpacer, style: widget.style, + simpleStyle: widget.simpleStyle, child: Padding( padding: widget.replyContent == null ? EdgeInsets.zero diff --git a/lib/src/widgets/chat/ds_location_message_bubble.widget.dart b/lib/src/widgets/chat/ds_location_message_bubble.widget.dart index 1fe96bab..4c8edd72 100644 --- a/lib/src/widgets/chat/ds_location_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_location_message_bubble.widget.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; import 'package:map_launcher/map_launcher.dart'; import '../../enums/ds_align.enum.dart'; @@ -9,6 +8,7 @@ import '../../models/ds_message_bubble_style.model.dart'; import '../../models/ds_reply_content.model.dart'; import '../../services/ds_auth.service.dart'; import '../../services/ds_bottom_sheet.service.dart'; +import '../../services/ds_navigation.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../utils/ds_utils.util.dart'; @@ -28,6 +28,7 @@ class DSLocationMessageBubble extends StatefulWidget { final String latitude; final String longitude; final List borderRadius; + final bool simpleStyle; final void Function(String)? onTapReply; DSLocationMessageBubble({ @@ -39,6 +40,7 @@ class DSLocationMessageBubble extends StatefulWidget { this.borderRadius = const [DSBorderRadius.all], DSMessageBubbleStyle? style, this.title, + this.simpleStyle = false, this.onTapReply, }) : style = style ?? DSMessageBubbleStyle(); @@ -83,6 +85,7 @@ class _DSLocationMessageBubbleState extends State { padding: EdgeInsets.zero, align: widget.align, style: widget.style, + simpleStyle: widget.simpleStyle, child: _buildBody(), ), ); @@ -163,7 +166,7 @@ class _DSLocationMessageBubbleState extends State { ), DSIconButton( onPressed: () { - Get.back(); + NavigationService.pop(); }, icon: const Icon(DSIcons.close_outline, color: DSColors.neutralDarkRooftop), @@ -198,7 +201,7 @@ class _DSLocationMessageBubbleState extends State { title: widget.title ?? '', ); - Get.back(); + NavigationService.pop(); }, title: DSBodyText( "location.open-with".translate() + " ${map.mapName}", diff --git a/lib/src/widgets/chat/ds_message_bubble.widget.dart b/lib/src/widgets/chat/ds_message_bubble.widget.dart index fec49333..89c2dba4 100644 --- a/lib/src/widgets/chat/ds_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_message_bubble.widget.dart @@ -20,12 +20,14 @@ class DSMessageBubble extends StatelessWidget { final double defaultMinSize; final DSMessageBubbleStyle style; final bool hasSpacer; + final bool simpleStyle; final void Function(String)? onTapReply; const DSMessageBubble({ super.key, required this.align, required this.child, + required this.style, this.replyContent, this.borderRadius = const [DSBorderRadius.all], this.padding = const EdgeInsets.symmetric( @@ -35,8 +37,8 @@ class DSMessageBubble extends StatelessWidget { this.shouldUseDefaultSize = false, this.defaultMaxSize = DSUtils.bubbleMaxSize, this.defaultMinSize = DSUtils.bubbleMinSize, - required this.style, this.hasSpacer = true, + this.simpleStyle = false, this.onTapReply, }); @@ -86,6 +88,7 @@ class DSMessageBubble extends StatelessWidget { replyContent: replyContent!, style: style, align: align, + simpleStyle: simpleStyle, onTap: onTapReply, ), child, diff --git a/lib/src/widgets/chat/ds_reply_container.widget.dart b/lib/src/widgets/chat/ds_reply_container.widget.dart index f994b4e0..efd9642d 100644 --- a/lib/src/widgets/chat/ds_reply_container.widget.dart +++ b/lib/src/widgets/chat/ds_reply_container.widget.dart @@ -6,32 +6,33 @@ import '../../models/ds_message_bubble_style.model.dart'; import '../../models/ds_reply_content.model.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; -import '../../utils/ds_message_content_type.util.dart'; -import '../texts/ds_body_text.widget.dart'; import '../texts/ds_caption_text.widget.dart'; +import '../utils/reply_content/ds_reply_preview.widget.dart'; class DSReplyContainer extends StatelessWidget { DSReplyContainer({ super.key, required this.replyContent, required this.align, + this.simpleStyle = false, DSMessageBubbleStyle? style, this.onTap, }) : style = style ?? DSMessageBubbleStyle(); final DSAlign align; final DSReplyContent replyContent; + final bool simpleStyle; final DSMessageBubbleStyle style; final void Function(String)? onTap; - Color get _foregroundColor => style.isLightBubbleBackground(align) - ? const Color.fromARGB(255, 39, 4, 4) - : DSColors.surface1; + late final isLightBubbleBackground = style.isLightBubbleBackground(align); @override Widget build(BuildContext context) { return GestureDetector( - onTap: () => onTap?.call(replyContent.inReplyTo.id), + onTap: () => (replyContent.inReplyTo.id?.isNotEmpty ?? false) + ? onTap?.call(replyContent.inReplyTo.id!) + : null, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -51,7 +52,7 @@ class DSReplyContainer extends StatelessWidget { children: [ Icon( DSIcons.undo_outline, - color: style.isLightBubbleBackground(align) + color: isLightBubbleBackground ? DSColors.neutralDarkCity : DSColors.neutralLightSnow, size: 24.0, @@ -60,7 +61,7 @@ class DSReplyContainer extends StatelessWidget { DSCaptionText( 'reply.text'.translate(), fontStyle: FontStyle.italic, - color: style.isLightBubbleBackground(align) + color: isLightBubbleBackground ? DSColors.neutralDarkCity : DSColors.neutralLightSnow, ), @@ -68,101 +69,34 @@ class DSReplyContainer extends StatelessWidget { ), ); - Widget _buildReplyContainer() => DecoratedBox( + Widget _buildReplyContainer() => Container( + clipBehavior: Clip.antiAlias, decoration: BoxDecoration( borderRadius: BorderRadius.circular(4.0), - border: Border.all( - color: style.isLightBubbleBackground(align) - ? DSColors.contentGhost - : DSColors.contentDisable, - ), - color: style.isLightBubbleBackground(align) - ? DSColors.surface3 + color: isLightBubbleBackground + ? DSColors.surface2 : DSColors.contentDefault, ), child: IntrinsicHeight( child: Row( children: [ Container( - decoration: const ShapeDecoration( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(8.0), - bottomLeft: Radius.circular(8.0), - ), - ), - color: DSColors.primary, - ), + color: isLightBubbleBackground + ? DSColors.primary + : DSColors.contentGhost, width: 4.0, ), - Flexible( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: _buildReply(), - ), - ), + _buildReply(), ], ), ), ); - Widget _buildReply() => switch (replyContent.inReplyTo.type) { - DSMessageContentType.textPlain => _buildTextPlain(), - DSMessageContentType.applicationJson => _buildApplicationJson(), - DSMessageContentType.select => _buidSelect(), - _ => _buildDefault(), - }; - - Widget _buidSelect() => DSBodyText( - replyContent.inReplyTo.value['text'], - color: _foregroundColor, - overflow: TextOverflow.visible, - ); - - Widget _buildApplicationJson() => Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (replyContent.inReplyTo.value['interactive']['body']?['text'] != - null) - DSBodyText( - replyContent.inReplyTo.value['interactive']['body']?['text'], - color: _foregroundColor, - overflow: TextOverflow.visible, - ), - if (replyContent.inReplyTo.value['interactive']['footer']?['text'] != - null) - DSCaptionText( - replyContent.inReplyTo.value['interactive']['footer']?['text'], - fontStyle: FontStyle.italic, - overflow: TextOverflow.visible, - color: _foregroundColor, - ), - ], - ); - - Widget _buildTextPlain() => replyContent.inReplyTo.value is String - ? DSBodyText( - replyContent.inReplyTo.value, - color: _foregroundColor, - overflow: TextOverflow.visible, - ) - : _buildDefault(); - - Widget _buildDefault() => Row( - children: [ - Icon( - DSIcons.warning_outline, - color: _foregroundColor, - size: 24.0, - ), - const SizedBox(width: 8.0), - Flexible( - child: DSBodyText( - 'reply.load-fail'.translate(), - overflow: TextOverflow.visible, - color: _foregroundColor, - ), - ), - ], + Widget _buildReply() => DSReplyPreview( + type: replyContent.inReplyTo.type, + content: replyContent.inReplyTo.value, + align: align, + simpleStyle: simpleStyle, + style: style, ); } diff --git a/lib/src/widgets/chat/ds_request_location_bubble.widget.dart b/lib/src/widgets/chat/ds_request_location_bubble.widget.dart index 342e1191..998c3f4d 100644 --- a/lib/src/widgets/chat/ds_request_location_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_request_location_bubble.widget.dart @@ -20,6 +20,7 @@ class DSRequestLocationBubble extends StatelessWidget { this.type = DSMessageContentType.textPlain, this.borderRadius = const [DSBorderRadius.all], this.showRequestLocationButton = false, + this.simpleStyle = false, DSMessageBubbleStyle? style, }) : style = style ?? DSMessageBubbleStyle(); @@ -31,6 +32,7 @@ class DSRequestLocationBubble extends StatelessWidget { final List borderRadius; final bool showRequestLocationButton; final DSMessageBubbleStyle style; + final bool simpleStyle; @override Widget build(BuildContext context) { @@ -53,6 +55,7 @@ class DSRequestLocationBubble extends StatelessWidget { align: align, borderRadius: borderRadius, style: style, + simpleStyle: simpleStyle, ), ), if (showRequestLocationButton) diff --git a/lib/src/widgets/chat/ds_text_message_bubble.widget.dart b/lib/src/widgets/chat/ds_text_message_bubble.widget.dart index 9803bb10..84ea4da4 100644 --- a/lib/src/widgets/chat/ds_text_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_text_message_bubble.widget.dart @@ -21,6 +21,7 @@ class DSTextMessageBubble extends StatefulWidget { final bool showSelect; final void Function(String, Map)? onSelected; final DSMessageBubbleStyle style; + final bool simpleStyle; final void Function(String)? onTapReply; DSTextMessageBubble({ @@ -33,6 +34,7 @@ class DSTextMessageBubble extends StatefulWidget { this.hasSpacer = true, this.showSelect = false, this.onSelected, + this.simpleStyle = false, DSMessageBubbleStyle? style, this.onTapReply, }) : style = style ?? DSMessageBubbleStyle(); @@ -67,6 +69,7 @@ class _DSTextMessageBubbleState extends State { style: widget.style, hasSpacer: widget.hasSpacer, replyContent: widget.replyContent, + simpleStyle: widget.simpleStyle, child: _buildText(), ); } diff --git a/lib/src/widgets/chat/ds_unsupported_content_message_bubble.widget.dart b/lib/src/widgets/chat/ds_unsupported_content_message_bubble.widget.dart index 98daff98..7ed40e1c 100644 --- a/lib/src/widgets/chat/ds_unsupported_content_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_unsupported_content_message_bubble.widget.dart @@ -18,6 +18,7 @@ class DSUnsupportedContentMessageBubble extends StatelessWidget { final TextOverflow overflow; final List borderRadius; final DSMessageBubbleStyle style; + final bool simpleStyle; DSUnsupportedContentMessageBubble({ super.key, @@ -27,6 +28,7 @@ class DSUnsupportedContentMessageBubble extends StatelessWidget { this.replyContent, this.overflow = TextOverflow.ellipsis, this.borderRadius = const [DSBorderRadius.all], + this.simpleStyle = false, DSMessageBubbleStyle? style, }) : style = style ?? DSMessageBubbleStyle(); @@ -41,6 +43,7 @@ class DSUnsupportedContentMessageBubble extends StatelessWidget { align: align, style: style, replyContent: replyContent, + simpleStyle: simpleStyle, child: Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/src/widgets/chat/ds_weblink_message_bubble.widget.dart b/lib/src/widgets/chat/ds_weblink_message_bubble.widget.dart index c9b1db3b..5e8ff4a1 100644 --- a/lib/src/widgets/chat/ds_weblink_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_weblink_message_bubble.widget.dart @@ -33,6 +33,9 @@ class DSWeblinkMessageBubble extends StatelessWidget { /// replyContent final DSReplyContent? replyContent; + /// simpleStyle + final bool simpleStyle; + /// Callback function to be executed when the reply button is tapped. final void Function(String)? onTapReply; @@ -44,6 +47,7 @@ class DSWeblinkMessageBubble extends StatelessWidget { required this.url, this.replyContent, this.borderRadius = const [DSBorderRadius.all], + this.simpleStyle = false, DSMessageBubbleStyle? style, this.onTapReply, }) : style = style ?? DSMessageBubbleStyle(); @@ -62,6 +66,7 @@ class DSWeblinkMessageBubble extends StatelessWidget { replyContent: replyContent, borderRadius: borderRadius, style: style, + simpleStyle: simpleStyle, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/src/widgets/chat/reply/ds_in_reply_content.widget.dart b/lib/src/widgets/chat/reply/ds_in_reply_content.widget.dart new file mode 100644 index 00000000..c23424c5 --- /dev/null +++ b/lib/src/widgets/chat/reply/ds_in_reply_content.widget.dart @@ -0,0 +1,36 @@ +import 'package:flutter/widgets.dart'; + +class DSInReplyContent extends StatelessWidget { + const DSInReplyContent({ + super.key, + required this.child, + this.leading, + this.trailing, + }); + + final Widget child; + final Widget? leading; + final Widget? trailing; + + @override + Widget build(BuildContext context) { + return Flexible( + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (leading != null) leading!, + Expanded( + child: Padding( + padding: const EdgeInsets.all( + 8.0, + ), + child: child, + ), + ), + if (trailing != null) trailing!, + ], + ), + ); + } +} diff --git a/lib/src/widgets/chat/video/ds_video_error.dialog.dart b/lib/src/widgets/chat/video/ds_video_error.dialog.dart index a4b173a2..7f66f195 100644 --- a/lib/src/widgets/chat/video/ds_video_error.dialog.dart +++ b/lib/src/widgets/chat/video/ds_video_error.dialog.dart @@ -1,11 +1,12 @@ import 'dart:convert'; import 'package:crypto/crypto.dart'; -import 'package:get/get.dart'; import '../../../extensions/ds_localization.extension.dart'; +import '../../../services/ds_context.service.dart'; import '../../../services/ds_dialog.service.dart'; import '../../../services/ds_file.service.dart'; +import '../../../services/ds_navigation.service.dart'; import '../../../utils/ds_directory_formatter.util.dart'; import '../../buttons/ds_primary_button.widget.dart'; import '../../buttons/ds_secondary_button.widget.dart'; @@ -20,7 +21,7 @@ abstract class DSVideoErrorDialog { text: 'video-error.reproduction-message'.translate(), primaryButton: DSPrimaryButton( onPressed: () async { - Get.back(); + NavigationService.pop(); final cachePath = await DSDirectoryFormatter.getCachePath( type: 'video/mp4', @@ -36,10 +37,10 @@ abstract class DSVideoErrorDialog { }, label: 'message.yes'.translate()), secondaryButton: DSSecondaryButton( - onPressed: () => Get.back(), + onPressed: () => NavigationService.pop(), label: 'message.no'.translate(), ), - context: Get.context!, + context: DSContextService.context!, ).showError(); } } diff --git a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart index 946cc9f4..95bf3e29 100644 --- a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart @@ -61,6 +61,9 @@ class DSVideoMessageBubble extends StatefulWidget { /// Title of the video which will be displayed inside the message bubble. final String? title; + /// simpleStyle + final bool simpleStyle; + /// Callback function to be executed when the reply button is tapped. final void Function(String)? onTapReply; @@ -80,10 +83,11 @@ class DSVideoMessageBubble extends StatefulWidget { this.text, this.borderRadius = const [DSBorderRadius.all], this.shouldAuthenticate = false, - DSMessageBubbleStyle? style, this.isUploading = false, this.replyContent, this.title, + this.simpleStyle = false, + DSMessageBubbleStyle? style, this.onTapReply, }) : style = style ?? DSMessageBubbleStyle(); @@ -149,6 +153,7 @@ class _DSVideoMessageBubbleState extends State borderRadius: widget.borderRadius, padding: EdgeInsets.zero, style: widget.style, + simpleStyle: widget.simpleStyle, child: LayoutBuilder( builder: (_, constraints) => Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/src/widgets/chat/video/ds_video_player.widget.dart b/lib/src/widgets/chat/video/ds_video_player.widget.dart index 6799b0ca..e7220dd3 100644 --- a/lib/src/widgets/chat/video/ds_video_player.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_player.widget.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import '../../../controllers/ds_video_player.controller.dart'; +import '../../../services/ds_navigation.service.dart'; import '../../../themes/colors/ds_colors.theme.dart'; import '../../../themes/icons/ds_icons.dart'; import '../../../themes/system_overlay/ds_system_overlay.style.dart'; @@ -31,7 +32,7 @@ class DSVideoPlayer extends StatelessWidget { required String url, this.appBarPhotoUri, this.shouldAuthenticate = false, - }) : controller = Get.put( + }) : controller = Get.put( DSVideoPlayerController( url: url, ), @@ -43,8 +44,17 @@ class DSVideoPlayer extends StatelessWidget { return AnnotatedRegion( value: overlayStyle, - child: WillPopScope( - onWillPop: () => Get.delete(), + child: PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) async { + if (didPop) { + return; + } + + if (await Get.delete()) { + NavigationService.pop(result); + } + }, child: Scaffold( backgroundColor: Colors.black, appBar: DSHeader( @@ -52,11 +62,13 @@ class DSVideoPlayer extends StatelessWidget { title: appBarText, customerUri: appBarPhotoUri, customerName: appBarText, - backgroundColor: Colors.black.withOpacity(.7), + backgroundColor: Colors.black.withValues( + alpha: .7, + ), systemUiOverlayStyle: overlayStyle, onBackButtonPressed: () { Get.delete(); - Get.back(); + NavigationService.pop(); }, ), body: Obx( diff --git a/lib/src/widgets/fields/ds_input_container.widget.dart b/lib/src/widgets/fields/ds_input_container.widget.dart index 2309a8cd..a99c779d 100644 --- a/lib/src/widgets/fields/ds_input_container.widget.dart +++ b/lib/src/widgets/fields/ds_input_container.widget.dart @@ -11,6 +11,7 @@ class DSInputContainer extends StatelessWidget { final bool? hasFocus; final DSInputContainerShape shape; final bool hasError; + final double minHeight; const DSInputContainer({ super.key, @@ -20,6 +21,7 @@ class DSInputContainer extends StatelessWidget { this.isEnabled = true, this.shape = DSInputContainerShape.rectangle, this.hasError = false, + this.minHeight = 44.0, }); @override @@ -47,8 +49,8 @@ class DSInputContainer extends StatelessWidget { : DSColors.neutralLightWhisper, ), child: Container( - constraints: const BoxConstraints( - minHeight: 44.0, + constraints: BoxConstraints( + minHeight: minHeight, ), padding: padding, child: child, diff --git a/lib/src/widgets/radio/ds_radio.widget.dart b/lib/src/widgets/radio/ds_radio.widget.dart index 0b615bf3..92cbaa50 100644 --- a/lib/src/widgets/radio/ds_radio.widget.dart +++ b/lib/src/widgets/radio/ds_radio.widget.dart @@ -68,25 +68,25 @@ class _RadioState extends State> @override bool? get value => widget._selected; - MaterialStateProperty get _widgetFillColor { - return MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.disabled)) { + WidgetStateProperty get _widgetFillColor { + return WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { return null; } - if (states.contains(MaterialState.selected)) { + if (states.contains(WidgetState.selected)) { return widget._activeColor; } return null; }); } - MaterialStateProperty get _defaultFillColor { + WidgetStateProperty get _defaultFillColor { final ThemeData themeData = Theme.of(context); - return MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.disabled)) { + return WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { return themeData.disabledColor; } - if (states.contains(MaterialState.selected)) { + if (states.contains(WidgetState.selected)) { return themeData.colorScheme.secondary; } return themeData.unselectedWidgetColor; @@ -116,23 +116,23 @@ class _RadioState extends State> } size += effectiveVisualDensity.baseSizeAdjustment; - final MaterialStateProperty effectiveMouseCursor = - MaterialStateProperty.resolveWith( - (Set states) { - return MaterialStateProperty.resolveAs( + final WidgetStateProperty effectiveMouseCursor = + WidgetStateProperty.resolveWith( + (Set states) { + return WidgetStateProperty.resolveAs( widget.mouseCursor, states) ?? themeData.radioTheme.mouseCursor?.resolve(states) ?? - MaterialStateProperty.resolveAs( - MaterialStateMouseCursor.clickable, states); + WidgetStateProperty.resolveAs( + WidgetStateMouseCursor.clickable, states); }); _painter.isEnabled = widget.isEnabled; // Colors need to be resolved in selected and non selected states separately // so that they can be lerped between. - final Set activeStates = states..add(MaterialState.selected); - final Set inactiveStates = states - ..remove(MaterialState.selected); + final Set activeStates = states..add(WidgetState.selected); + final Set inactiveStates = states + ..remove(WidgetState.selected); final Color effectiveActiveColor = widget.fillColor?.resolve(activeStates) ?? _widgetFillColor.resolve(activeStates) ?? @@ -144,29 +144,29 @@ class _RadioState extends State> themeData.radioTheme.fillColor?.resolve(inactiveStates) ?? _defaultFillColor.resolve(inactiveStates); - final Set focusedStates = states..add(MaterialState.focused); + final Set focusedStates = states..add(WidgetState.focused); final Color effectiveFocusOverlayColor = widget.overlayColor?.resolve(focusedStates) ?? widget.focusColor ?? themeData.radioTheme.overlayColor?.resolve(focusedStates) ?? themeData.focusColor; - final Set hoveredStates = states..add(MaterialState.hovered); + final Set hoveredStates = states..add(WidgetState.hovered); final Color effectiveHoverOverlayColor = widget.overlayColor?.resolve(hoveredStates) ?? widget.hoverColor ?? themeData.radioTheme.overlayColor?.resolve(hoveredStates) ?? themeData.hoverColor; - final Set activePressedStates = activeStates - ..add(MaterialState.pressed); + final Set activePressedStates = activeStates + ..add(WidgetState.pressed); final Color effectiveActivePressedOverlayColor = widget.overlayColor?.resolve(activePressedStates) ?? themeData.radioTheme.overlayColor?.resolve(activePressedStates) ?? effectiveActiveColor.withAlpha(kRadialReactionAlpha); - final Set inactivePressedStates = inactiveStates - ..add(MaterialState.pressed); + final Set inactivePressedStates = inactiveStates + ..add(WidgetState.pressed); final Color effectiveInactivePressedOverlayColor = widget.overlayColor?.resolve(inactivePressedStates) ?? themeData.radioTheme.overlayColor?.resolve(inactivePressedStates) ?? @@ -193,8 +193,8 @@ class _RadioState extends State> themeData.radioTheme.splashRadius ?? kRadialReactionRadius ..downPosition = downPosition - ..isFocused = states.contains(MaterialState.focused) - ..isHovered = states.contains(MaterialState.hovered) + ..isFocused = states.contains(WidgetState.focused) + ..isHovered = states.contains(WidgetState.hovered) ..activeColor = widget._activeColor ..inactiveColor = effectiveInactiveColor, ), diff --git a/lib/src/widgets/radio/ds_radio_tile.widget.dart b/lib/src/widgets/radio/ds_radio_tile.widget.dart index 57c6a9f5..8bab86ef 100644 --- a/lib/src/widgets/radio/ds_radio_tile.widget.dart +++ b/lib/src/widgets/radio/ds_radio_tile.widget.dart @@ -28,7 +28,7 @@ class DSRadioTile extends StatelessWidget { /// Determines the grouping of buttons allowing one of them to be selected /// - /// The type determines which type of variable to use as [value], + /// The <T> type determines which type of variable to use as [value], /// which can be int, String, or even an object. final T? groupValue; diff --git a/lib/src/widgets/switch/ds_switch.widget.dart b/lib/src/widgets/switch/ds_switch.widget.dart index c662d04b..ce075e1e 100644 --- a/lib/src/widgets/switch/ds_switch.widget.dart +++ b/lib/src/widgets/switch/ds_switch.widget.dart @@ -68,8 +68,6 @@ class DSSwitch extends DSSwitchBase { return isEnabled ? _activeColor : DSColors.primaryLight; case (false): return isEnabled ? _inactiveColor : DSColors.neutralMediumWave; - default: - return _activeColor; } } } diff --git a/lib/src/widgets/tags/ds_input_chip.widget.dart b/lib/src/widgets/tags/ds_input_chip.widget.dart index 271b142d..1c1739a8 100644 --- a/lib/src/widgets/tags/ds_input_chip.widget.dart +++ b/lib/src/widgets/tags/ds_input_chip.widget.dart @@ -104,7 +104,9 @@ class _DSInputChipState extends State { size: 32.0, icon: Icon( DSIcons.error_solid, - color: DSColors.neutralDarkCity.withOpacity(0.6), + color: DSColors.neutralDarkCity.withValues( + alpha: 0.6, + ), ), onPressed: () => widget.onDeleted?.call(index), ), diff --git a/lib/src/widgets/toast/ds_toast.widget.dart b/lib/src/widgets/toast/ds_toast.widget.dart index e2e8ddbf..e6b79f8b 100644 --- a/lib/src/widgets/toast/ds_toast.widget.dart +++ b/lib/src/widgets/toast/ds_toast.widget.dart @@ -2,12 +2,12 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:get/get.dart'; import 'package:simple_animations/simple_animations.dart'; import '../../enums/ds_toast_action_type.enum.dart'; import '../../enums/ds_toast_type.enum.dart'; import '../../models/ds_toast_props.model.dart'; +import '../../services/ds_context.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../utils/ds_utils.util.dart'; @@ -201,7 +201,7 @@ class _DSToastState extends State with AutomaticKeepAliveClientMixin { Widget build(BuildContext context) { super.build(context); - double start = (MediaQuery.of(Get.context!).size.width) * -1.0; + double start = (MediaQuery.of(DSContextService.context!).size.width) * -1.0; double end = 0.0; final duration = props.toastDuration ?? diff --git a/lib/src/widgets/utils/ds_active_message_reply_content.widget.dart b/lib/src/widgets/utils/ds_active_message_reply_content.widget.dart new file mode 100644 index 00000000..67716285 --- /dev/null +++ b/lib/src/widgets/utils/ds_active_message_reply_content.widget.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; + +import '../../enums/ds_align.enum.dart'; +import '../../extensions/ds_localization.extension.dart'; +import '../../models/ds_active_message.model.dart'; +import '../../models/ds_message_bubble_style.model.dart'; +import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/icons/ds_icons.dart'; +import '../chat/reply/ds_in_reply_content.widget.dart'; +import '../texts/ds_body_text.widget.dart'; +import '../texts/ds_caption_text.widget.dart'; + +class DSActiveMessageContentReply extends StatelessWidget { + DSActiveMessageContentReply({ + super.key, + required this.activeMessage, + required this.align, + this.simpleStyle = false, + this.isPreview = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final DSActiveMessage activeMessage; + final DSAlign align; + final bool simpleStyle; + final bool isPreview; + final DSMessageBubbleStyle style; + + late final _foregroundColor = style.isLightBubbleBackground(align) + ? const Color.fromARGB(255, 39, 4, 4) + : DSColors.surface1; + + late final templateTitle = + activeMessage.template?.name ?? 'unsupported-content.text'.translate(); + + late final templateContent = _buildTemplateContent(); + + String _buildTemplateContent() { + var componentTemplateBody = activeMessage.templateContent?.components + ?.where((component) => component['type'] == 'BODY') + .toList(); + var bodyFilledVariables = activeMessage.template?.components + ?.where((component) => component['type'] == 'body') + .toList(); + + String? content; + + if (componentTemplateBody?.isNotEmpty ?? false) { + content = componentTemplateBody?[0]['text'] ?? ''; + + if (bodyFilledVariables?.isNotEmpty ?? false) { + final params = bodyFilledVariables?[0]['parameters']; + + final regexFindVariablesInText = RegExp(r'/\{\{(\d+)\}\}/g'); + + var index = 1; + content = content?.replaceAllMapped(regexFindVariablesInText, (match) { + final variable = params[index - 1]; + return variable && variable.text ? variable.text : match; + }); + } + } + + // componentTemplateBody = this.sanitize(componentTemplateBody) + + return content ?? ''; + } + + @override + Widget build(BuildContext context) { + return DSInReplyContent( + leading: Padding( + padding: const EdgeInsets.only( + left: 8.0, + ), + child: Icon( + DSIcons.paperplane_outline, + color: _foregroundColor, + size: isPreview ? 18.0 : 24.0, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (!simpleStyle) + DSCaptionText( + templateTitle, + color: _foregroundColor, + ), + isPreview + ? DSCaptionText( + templateContent, + color: _foregroundColor, + ) + : DSBodyText( + templateContent, + color: _foregroundColor, + overflow: TextOverflow.visible, + ), + ], + ), + ); + } +} diff --git a/lib/src/widgets/utils/ds_audio_duration_view.widget.dart b/lib/src/widgets/utils/ds_audio_duration_view.widget.dart new file mode 100644 index 00000000..a51ef110 --- /dev/null +++ b/lib/src/widgets/utils/ds_audio_duration_view.widget.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:just_audio/just_audio.dart'; + +import '../../models/ds_media_link.model.dart'; +import '../../utils/ds_utils.util.dart'; +import '../texts/ds_caption_small_text.widget.dart'; + +class DSAudioDurationView extends StatefulWidget { + const DSAudioDurationView({ + super.key, + required this.media, + required this.foreground, + }); + + final DSMediaLink media; + final Color foreground; + + @override + createState() => _DSAudioDurationViewState(); +} + +class _DSAudioDurationViewState extends State { + final audioPlayer = AudioPlayer(); + final subtitle = ValueNotifier(''); + + late final _mediaLink = widget.media; + late final _foregroundColor = widget.foreground; + + @override + void initState() { + super.initState(); + + _loadAudioDuration(); + } + + @override + dispose() { + audioPlayer.dispose(); + subtitle.dispose(); + + super.dispose(); + } + + Future _loadAudioDuration() async { + try { + await audioPlayer.setUrl(_mediaLink.previewUri ?? _mediaLink.uri); + + final duration = audioPlayer.duration; + subtitle.value = RegExp(r'((^0*[1-9]\d*:)?\d{2}:\d{2})\.\d+$') + .firstMatch("$duration") + ?.group(1) ?? + "$duration"; + } catch (e) { + debugPrint('Error loading audio: $e'); + } + } + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: subtitle, + builder: (_, value, __) => AnimatedSwitcher( + duration: DSUtils.defaultAnimationDuration, + child: value.isNotEmpty + ? DSCaptionSmallText( + value, + color: _foregroundColor, + height: 1.0, + ) + : const SizedBox.shrink(), + ), + ); + } +} diff --git a/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart b/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart index af5679ac..d3dd56a3 100644 --- a/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart +++ b/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart @@ -5,6 +5,8 @@ import 'package:get/get.dart'; import '../../extensions/ds_localization.extension.dart'; import '../../models/ds_country.model.dart'; import '../../services/ds_bottom_sheet.service.dart'; +import '../../services/ds_context.service.dart'; +import '../../services/ds_navigation.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../utils/ds_utils.util.dart'; @@ -45,7 +47,7 @@ abstract class DSBottomSheetCountries { ), DSIconButton( onPressed: () { - Get.back(); + NavigationService.pop(); }, icon: const Icon( DSIcons.close_outline, @@ -76,7 +78,7 @@ abstract class DSBottomSheetCountries { const DSDivider(), ], ), - context: Get.context!, + context: DSContextService.context!, builder: (_) => _builderCountries(), ).show(); } @@ -113,7 +115,7 @@ abstract class DSBottomSheetCountries { value: country, onChanged: (value) { selectedCountry.value = value!; - Get.back(result: selectedCountry.value); + NavigationService.pop(selectedCountry.value); }, title: Row( children: [ diff --git a/lib/src/widgets/utils/ds_cached_video_thumbnail_view.widget.dart b/lib/src/widgets/utils/ds_cached_video_thumbnail_view.widget.dart new file mode 100644 index 00000000..dc19ba1d --- /dev/null +++ b/lib/src/widgets/utils/ds_cached_video_thumbnail_view.widget.dart @@ -0,0 +1,118 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../controllers/chat/ds_video_message_bubble.controller.dart'; +import '../../enums/ds_align.enum.dart'; +import '../../models/ds_message_bubble_style.model.dart'; +import '../../services/ds_auth.service.dart'; +import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/icons/ds_icons.dart'; + +class DSCachedVideoThumbnailView extends StatefulWidget { + final int mediaSize; + final String url; + final String type; + final DSAlign align; + final double? width; + final double? height; + final BoxFit? fit; + final void Function()? onError; + final DSMessageBubbleStyle style; + final bool shouldAuthenticate; + + final Widget Function( + BuildContext context, + String url, + ) placeholder; + + final Widget Function( + BuildContext context, + String url, + dynamic error, + )? errorWidget; + + DSCachedVideoThumbnailView({ + super.key, + required this.url, + required this.align, + required this.mediaSize, + required this.type, + required this.placeholder, + this.width, + this.height, + this.fit = BoxFit.cover, + this.errorWidget, + this.onError, + this.shouldAuthenticate = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + @override + State createState() => + _DSCachedVideoThumbnailViewState(); +} + +class _DSCachedVideoThumbnailViewState + extends State { + late final _controller = DSVideoMessageBubbleController( + url: widget.url, + mediaSize: widget.mediaSize, + httpHeaders: widget.shouldAuthenticate ? DSAuthService.httpHeaders : null, + type: widget.type, + ); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: widget.width, + height: widget.height, + child: Obx( + () => widget.url.isEmpty + ? _buildError(context) + : _controller.isLoadingThumbnail.value + ? widget.placeholder(context, widget.url) + : _controller.thumbnail.isEmpty + ? Center( + child: Icon( + DSIcons.video_broken_outline, + color: + widget.style.isLightBubbleBackground(widget.align) + ? DSColors.neutralMediumElephant + : DSColors.neutralMediumCloud, + ), + ) + : Image.file( + File( + _controller.thumbnail.value, + ), + width: widget.width, + height: widget.height, + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildError(BuildContext context) { + widget.onError?.call(); + + return widget.errorWidget != null + ? widget.errorWidget!(context, widget.url, null) + : _defaultErrorWidget(); + } + + Widget _defaultErrorWidget() { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 80), + child: Icon( + DSIcons.file_image_broken_outline, + color: widget.style.isLightBubbleBackground(widget.align) + ? DSColors.neutralMediumElephant + : DSColors.neutralMediumCloud, + size: 75, + ), + ); + } +} diff --git a/lib/src/widgets/utils/ds_card.widget.dart b/lib/src/widgets/utils/ds_card.widget.dart index 86dd9273..4ff2d3d1 100644 --- a/lib/src/widgets/utils/ds_card.widget.dart +++ b/lib/src/widgets/utils/ds_card.widget.dart @@ -51,6 +51,7 @@ class DSCard extends StatelessWidget { this.showRequestLocationButton = false, this.replyContent, this.isUploading = false, + this.simpleStyle = false, this.onAsyncFetchSession, this.onTapReply, }) : style = style ?? DSMessageBubbleStyle(); @@ -70,6 +71,7 @@ class DSCard extends StatelessWidget { final bool showRequestLocationButton; final DSReplyContent? replyContent; final bool isUploading; + final bool simpleStyle; final Future Function(String)? onAsyncFetchSession; final void Function(String)? onTapReply; @@ -88,6 +90,7 @@ class DSCard extends StatelessWidget { borderRadius: borderRadius, style: style, replyContent: replyContent, + simpleStyle: simpleStyle, onTapReply: onTapReply, ); @@ -110,6 +113,8 @@ class DSCard extends StatelessWidget { messageId: messageId, customer: customer, replyContent: DSUtils.shouldShowReplyContainer ? replyContent : null, + simpleStyle: simpleStyle, + isUploading: isUploading, onTapReply: onTapReply, ); @@ -143,6 +148,7 @@ class DSCard extends StatelessWidget { replyContent: replyContent, borderRadius: borderRadius, style: style, + simpleStyle: simpleStyle, onTapReply: onTapReply, ); @@ -155,15 +161,18 @@ class DSCard extends StatelessWidget { align: align, style: style, replyContent: replyContent, + simpleStyle: simpleStyle, onTapReply: onTapReply, ); case DSMessageContentType.ticket: - return DSTicketMessage( - messageType: DSTicketMessageType.forwardedTicket, - ticketId: content['formattedTicketId'], - chatbotIdentity: content['ownerIdentity'], - contentStatus: content['status'], - ); + return simpleStyle + ? const SizedBox.shrink() + : DSTicketMessage( + messageType: DSTicketMessageType.forwardedTicket, + ticketId: content['formattedTicketId'], + chatbotIdentity: content['ownerIdentity'], + contentStatus: content['status'], + ); case DSMessageContentType.input: return _buildRequestLocation(); @@ -176,6 +185,7 @@ class DSCard extends StatelessWidget { content: content, status: status, avatarConfig: avatarConfig, + simpleStyle: simpleStyle, onTapReply: onTapReply, ); @@ -195,6 +205,7 @@ class DSCard extends StatelessWidget { replyContent: replyContent, borderRadius: borderRadius, style: style, + simpleStyle: simpleStyle, ); } } @@ -222,6 +233,7 @@ class DSCard extends StatelessWidget { onSelected: onSelected, onOpenLink: onOpenLink, mediaType: documentSelectModel.header.mediaLink.type, + simpleStyle: simpleStyle, onTapReply: onTapReply, ); } @@ -241,6 +253,7 @@ class DSCard extends StatelessWidget { replyContent: replyContent, borderRadius: borderRadius, style: style, + simpleStyle: simpleStyle, ), ), Visibility( @@ -264,6 +277,7 @@ class DSCard extends StatelessWidget { replyContent: replyContent, onSelected: onSelected, style: style, + simpleStyle: simpleStyle, ); } @@ -277,6 +291,7 @@ class DSCard extends StatelessWidget { replyContent: replyContent, style: style, borderRadius: borderRadius, + simpleStyle: simpleStyle, ); } @@ -305,6 +320,7 @@ class DSCard extends StatelessWidget { replyContent: replyContent, uniqueId: messageId, shouldAuthenticate: shouldAuthenticate, + simpleStyle: simpleStyle, onTapReply: onTapReply, ); } else if (media.type.contains('image')) { @@ -326,6 +342,7 @@ class DSCard extends StatelessWidget { shouldAuthenticate: shouldAuthenticate, mediaType: media.type, isUploading: isUploading, + simpleStyle: simpleStyle, onTapReply: onTapReply, ); } else if (media.type.contains('video')) { @@ -347,6 +364,7 @@ class DSCard extends StatelessWidget { mediaSize: size, shouldAuthenticate: shouldAuthenticate, isUploading: isUploading, + simpleStyle: simpleStyle, onTapReply: onTapReply, ); } else { @@ -362,6 +380,7 @@ class DSCard extends StatelessWidget { style: style, shouldAuthenticate: shouldAuthenticate, isUploading: isUploading, + simpleStyle: simpleStyle, ); } } @@ -380,6 +399,7 @@ class DSCard extends StatelessWidget { borderRadius: borderRadius, style: style, showRequestLocationButton: showRequestLocationButton, + simpleStyle: simpleStyle, ); } } diff --git a/lib/src/widgets/utils/ds_chip.widget.dart b/lib/src/widgets/utils/ds_chip.widget.dart index 22c7bdcc..58f2389f 100644 --- a/lib/src/widgets/utils/ds_chip.widget.dart +++ b/lib/src/widgets/utils/ds_chip.widget.dart @@ -12,6 +12,7 @@ class DSChip extends StatelessWidget { final VoidCallback? onTap; final Widget? trailingIcon; final EdgeInsetsGeometry? textPadding; + final EdgeInsetsGeometry? margin; final double? size; const DSChip({ @@ -25,6 +26,7 @@ class DSChip extends StatelessWidget { this.border, this.onTap, this.textPadding, + this.margin, this.size, }); @@ -36,6 +38,7 @@ class DSChip extends StatelessWidget { height: size, width: size, padding: padding, + margin: margin, decoration: text == null ? BoxDecoration( color: background, diff --git a/lib/src/widgets/utils/ds_expanded_image.widget.dart b/lib/src/widgets/utils/ds_expanded_image.widget.dart index 4a14c6aa..93db5296 100644 --- a/lib/src/widgets/utils/ds_expanded_image.widget.dart +++ b/lib/src/widgets/utils/ds_expanded_image.widget.dart @@ -5,8 +5,18 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:pinch_zoom/pinch_zoom.dart'; -import '../../../blip_ds.dart'; +import '../../enums/ds_align.enum.dart'; +import '../../models/ds_message_bubble_style.model.dart'; +import '../../services/ds_context.service.dart'; +import '../../services/ds_navigation.service.dart'; +import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/icons/ds_icons.dart'; +import '../../themes/system_overlay/ds_system_overlay.style.dart'; +import '../../utils/ds_utils.util.dart'; +import '../animations/ds_spinner_loading.widget.dart'; import '../animations/ds_uploading.widget.dart'; +import 'ds_cached_network_image_view.widget.dart'; +import 'ds_header.widget.dart'; class DSExpandedImage extends StatelessWidget { final String appBarText; @@ -111,7 +121,7 @@ class DSExpandedImage extends StatelessWidget { } Future _expandImage() => showGeneralDialog( - context: Get.context!, + context: DSContextService.context!, barrierDismissible: false, transitionDuration: DSUtils.defaultAnimationDuration, transitionBuilder: (_, animation, __, child) => FadeTransition( @@ -135,8 +145,10 @@ class DSExpandedImage extends StatelessWidget { title: appBarText, customerUri: appBarPhotoUri, customerName: appBarText, - backgroundColor: Colors.black.withOpacity(0.7), - onBackButtonPressed: Get.back, + backgroundColor: Colors.black.withValues( + alpha: 0.7, + ), + onBackButtonPressed: NavigationService.pop, systemUiOverlayStyle: DSSystemOverlayStyle.light, ), body: GestureDetector( diff --git a/lib/src/widgets/utils/ds_group_card.widget.dart b/lib/src/widgets/utils/ds_group_card.widget.dart index 446bed27..3b9126f3 100644 --- a/lib/src/widgets/utils/ds_group_card.widget.dart +++ b/lib/src/widgets/utils/ds_group_card.widget.dart @@ -13,6 +13,7 @@ import '../../themes/icons/ds_icons.dart'; import '../../themes/texts/styles/ds_caption_small_text_style.theme.dart'; import '../../utils/ds_message_content_type.util.dart'; import '../../utils/ds_utils.util.dart'; +import '../animations/ds_reply_swipe.widget.dart'; import '../buttons/ds_button.widget.dart'; import '../chat/ds_message_bubble_detail.widget.dart'; import '../chat/ds_quick_reply.widget.dart'; @@ -59,12 +60,15 @@ class DSGroupCard extends StatefulWidget { this.onOpenLink, this.hideOptions = false, this.showMessageStatus = true, + this.simpleStyle = false, this.avatarConfig = const DSMessageBubbleAvatarConfig(), this.onInfinitScroll, this.shrinkWrap = false, + this.scrollController, + this.onAsyncFetchSession, + this.onReply, DSMessageBubbleStyle? style, bool Function(DSMessageItem, DSMessageItem)? compareMessages, - this.onAsyncFetchSession, }) : compareMessages = compareMessages ?? _defaultCompareMessageFuntion, style = style ?? DSMessageBubbleStyle(); @@ -76,11 +80,14 @@ class DSGroupCard extends StatefulWidget { final void Function(Map)? onOpenLink; final bool hideOptions; final bool showMessageStatus; + final bool simpleStyle; final DSMessageBubbleStyle style; final DSMessageBubbleAvatarConfig avatarConfig; final void Function()? onInfinitScroll; final bool shrinkWrap; + final AutoScrollController? scrollController; final Future Function(String)? onAsyncFetchSession; + final void Function(DSMessageItem)? onReply; @override State createState() => _DSGroupCardState(); @@ -94,12 +101,13 @@ class _DSGroupCardState extends State { @override void initState() { - controller = AutoScrollController( - suggestedRowHeight: 80, - viewportBoundaryGetter: () => - Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), - axis: Axis.vertical, - ); + controller = widget.scrollController ?? + AutoScrollController( + suggestedRowHeight: 80, + viewportBoundaryGetter: () => + Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), + axis: Axis.vertical, + ); controller.addListener(() { final nextPageTrigger = 0.90 * controller.position.maxScrollExtent; @@ -116,6 +124,7 @@ class _DSGroupCardState extends State { @override void dispose() { + controller.dispose(); super.dispose(); } @@ -136,7 +145,7 @@ class _DSGroupCardState extends State { key: widgets[index].key as ValueKey, controller: controller, index: index, - highlightColor: Colors.black.withOpacity(0.1), + highlightColor: Colors.black.withValues(alpha: 0.1), child: widgets[index], ); }, @@ -144,7 +153,9 @@ class _DSGroupCardState extends State { final valueKey = key as ValueKey; final index = widgets.indexWhere((widget) => (widget.key as ValueKey).value == valueKey.value); + if (index == -1) return null; + return index; }, ), @@ -256,8 +267,11 @@ class _DSGroupCardState extends State { List borderRadius = _getBorderRadius(length, msgCount, group['align']); + final messageId = + '${message.id ?? DSUtils.generateUniqueID()}-${message.isUploading}'; + final bubble = DSCard( - key: ValueKey('${message.id}-${message.isUploading}'), + key: ValueKey(messageId), type: message.type, content: message.content, align: message.align, @@ -267,12 +281,13 @@ class _DSGroupCardState extends State { avatarConfig: widget.avatarConfig, style: widget.style, onOpenLink: widget.onOpenLink, - messageId: message.id, + messageId: messageId, customer: message.customer, isUploading: message.isUploading, + simpleStyle: widget.simpleStyle, onAsyncFetchSession: widget.onAsyncFetchSession, onTapReply: (final inReplyToId) => - _onTapReply(inReplyToId, message.id!), + _onTapReply(inReplyToId, messageId), ); final isLastMsg = msgCount == length; @@ -285,8 +300,9 @@ class _DSGroupCardState extends State { ), ]; - if ((sentMessage && widget.avatarConfig.showSentAvatar) || - (!sentMessage && widget.avatarConfig.showReceivedAvatar)) { + if (!widget.simpleStyle && + ((sentMessage && widget.avatarConfig.showSentAvatar) || + (!sentMessage && widget.avatarConfig.showReceivedAvatar))) { columns.add( isLastMsg ? Align( @@ -304,7 +320,7 @@ class _DSGroupCardState extends State { : widget.avatarConfig.receivedName, ), ) - : const SizedBox(), + : const SizedBox.shrink(), ); } @@ -314,6 +330,24 @@ class _DSGroupCardState extends State { ), ); + items.insert( + 0, + DSReplySwipe( + key: ValueKey(messageId), + message: message, + onReply: widget.onReply, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Table( + columnWidths: + sentMessage ? sentColumnWidths : receivedColumnWidths, + defaultVerticalAlignment: TableCellVerticalAlignment.bottom, + children: rows, + ), + ), + ), + ); + if (isLastMsg && ((message.hideMessageDetail ?? false) ? false : true)) { final columns = [ @@ -332,33 +366,32 @@ class _DSGroupCardState extends State { if ((sentMessage && widget.avatarConfig.showSentAvatar) || (!sentMessage && widget.avatarConfig.showReceivedAvatar)) { columns.add( - const SizedBox(), + const SizedBox.shrink(), ); } - rows.add( - TableRow( - children: sentMessage ? columns : columns.reversed.toList(), + items.insert( + 0, + Padding( + key: ValueKey( + DSUtils.generateUniqueID(), + ), + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Table( + columnWidths: + sentMessage ? sentColumnWidths : receivedColumnWidths, + defaultVerticalAlignment: TableCellVerticalAlignment.bottom, + children: [ + TableRow( + children: + sentMessage ? columns : columns.reversed.toList(), + ), + ], + ), ), ); } - items.insert( - 0, - Padding( - key: ValueKey( - message.id ?? DSUtils.generateUniqueID(), - ), - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Table( - columnWidths: - sentMessage ? sentColumnWidths : receivedColumnWidths, - defaultVerticalAlignment: TableCellVerticalAlignment.bottom, - children: rows, - ), - ), - ); - final hideOptions = widget.documents.last != message; if (!hideOptions && message.type == DSMessageContentType.select && @@ -394,7 +427,7 @@ class _DSGroupCardState extends State { if (widget.avatarConfig.showReceivedAvatar) { columns.insert( 0, - const SizedBox(), + const SizedBox.shrink(), ); } @@ -490,6 +523,8 @@ class _DSGroupCardState extends State { final String inReplyToId, final String repliedId, ) async { + if (inReplyToId.isEmpty) return; + previousReplyId = repliedId; final index = widgets.indexWhere( diff --git a/lib/src/widgets/utils/ds_header.widget.dart b/lib/src/widgets/utils/ds_header.widget.dart index af567585..0c7a2d53 100644 --- a/lib/src/widgets/utils/ds_header.widget.dart +++ b/lib/src/widgets/utils/ds_header.widget.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import '../../services/ds_navigation.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../themes/system_overlay/ds_system_overlay.style.dart'; @@ -51,7 +52,7 @@ class DSHeader extends StatelessWidget implements PreferredSizeWidget { this.showBorder = true, this.visible = true, final SystemUiOverlayStyle? systemUiOverlayStyle, - }) : systemUiOverlayStyle = + }) : systemUiOverlayStyle = systemUiOverlayStyle ?? DSSystemOverlayStyle.dark { isBackgroundLight = backgroundColor.computeLuminance() > 0.5; } @@ -61,39 +62,28 @@ class DSHeader extends StatelessWidget implements PreferredSizeWidget { return AnimatedOpacity( opacity: visible ? 1.0 : 0.0, duration: DSUtils.defaultAnimationDuration, - child: Container( - decoration: BoxDecoration( - color: backgroundColor, - border: showBorder - ? Border( - bottom: BorderSide( - color: borderColor, - ), + child: SafeArea( + top: false, + bottom: false, + child: AppBar( + surfaceTintColor: Colors.transparent, + centerTitle: false, + automaticallyImplyLeading: false, + elevation: elevation, + backgroundColor: backgroundColor, + shadowColor: (elevation ?? 0) > 0 ? DSColors.neutralMediumWave : null, + bottom: bottomWidget != null + ? PreferredSize( + preferredSize: const Size.fromHeight(48), + child: bottomWidget!, ) : null, - ), - child: SafeArea( - top: false, - bottom: false, - child: AppBar( - centerTitle: false, - automaticallyImplyLeading: false, - elevation: elevation, - backgroundColor: Colors.transparent, - shadowColor: DSColors.neutralMediumWave, - bottom: bottomWidget != null - ? PreferredSize( - preferredSize: const Size.fromHeight(48), - child: bottomWidget!, - ) - : null, - actions: actions, - titleSpacing: 0, - leadingWidth: 40.0, - leading: _buildLeading(context), - title: _buildTitle(context), - systemOverlayStyle: systemUiOverlayStyle, - ), + actions: actions, + titleSpacing: 0, + leadingWidth: 40.0, + leading: _buildLeading(context), + title: _buildTitle(context), + systemOverlayStyle: systemUiOverlayStyle, ), ), ); @@ -146,7 +136,7 @@ class DSHeader extends StatelessWidget implements PreferredSizeWidget { splashRadius: 17, padding: EdgeInsets.zero, onPressed: visible - ? onBackButtonPressed ?? Navigator.of(context).pop + ? onBackButtonPressed ?? NavigationService.pop : null, iconSize: 28, icon: Icon( diff --git a/lib/src/widgets/utils/ds_progress_bar.widget.dart b/lib/src/widgets/utils/ds_progress_bar.widget.dart index 2679b5ce..186f5191 100644 --- a/lib/src/widgets/utils/ds_progress_bar.widget.dart +++ b/lib/src/widgets/utils/ds_progress_bar.widget.dart @@ -98,7 +98,9 @@ class _AnimatedBarWidgetState extends State child: Text( '/', style: TextStyle( - color: Colors.black.withOpacity(0.2), + color: Colors.black.withValues( + alpha: 0.2, + ), fontSize: 14.0, height: 1.0, ), diff --git a/lib/src/widgets/utils/ds_svg.widget.dart b/lib/src/widgets/utils/ds_svg.widget.dart new file mode 100644 index 00000000..b36c82f3 --- /dev/null +++ b/lib/src/widgets/utils/ds_svg.widget.dart @@ -0,0 +1,23 @@ +import 'dart:ui'; + +import 'package:flutter_svg/svg.dart'; + +import '../../themes/colors/ds_colors.theme.dart'; + +class DSSvg extends SvgPicture { + final Color color; + + DSSvg.asset( + super.assetName, { + super.key, + super.fit, + super.package, + super.height = 24.0, + this.color = DSColors.neutralDarkCity, + }) : super.asset( + colorFilter: ColorFilter.mode( + color, + BlendMode.srcIn, + ), + ); +} diff --git a/lib/src/widgets/utils/ds_user_avatar.widget.dart b/lib/src/widgets/utils/ds_user_avatar.widget.dart index 6d9dd186..8c461e4b 100644 --- a/lib/src/widgets/utils/ds_user_avatar.widget.dart +++ b/lib/src/widgets/utils/ds_user_avatar.widget.dart @@ -1,4 +1,5 @@ import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../../themes/colors/ds_colors.theme.dart'; @@ -6,10 +7,12 @@ import '../../themes/icons/ds_icons.dart'; import '../../themes/texts/styles/ds_body_text_style.theme.dart'; import '../../utils/ds_utils.util.dart'; import '../texts/ds_text.widget.dart'; +import 'ds_svg.widget.dart'; class DSUserAvatar extends StatelessWidget { final String? text; final Uri? uri; + final Uint8List? file; final double radius; final Color backgroundColor; final TextStyle textStyle; @@ -23,6 +26,7 @@ class DSUserAvatar extends StatelessWidget { super.key, this.text, this.uri, + this.file, this.radius = 25.0, this.backgroundColor = DSColors.primaryGreensTrue, TextStyle textStyle = _defaultTextStyle, @@ -32,29 +36,36 @@ class DSUserAvatar extends StatelessWidget { ); @override - Widget build(BuildContext context) => uri != null - ? CachedNetworkImage( - imageUrl: uri.toString(), - imageBuilder: (_, image) => CircleAvatar( - radius: radius, - backgroundColor: backgroundColor, - backgroundImage: image, - ), - progressIndicatorBuilder: (_, __, downloadProgress) { - final size = Size.fromRadius(radius); - - return SizedBox( - height: size.height, - width: size.width, - child: CircularProgressIndicator( - value: downloadProgress.progress, - strokeWidth: 1, - ), - ); - }, - errorWidget: (_, __, ___) => _defaultUserIcon, + Widget build(BuildContext context) => file != null + ? CircleAvatar( + radius: radius, + backgroundColor: backgroundColor, + backgroundImage: MemoryImage(file!), ) - : _defaultUserIcon; + : uri != null + ? CachedNetworkImage( + imageUrl: uri.toString(), + useOldImageOnUrlChange: true, + imageBuilder: (_, image) => CircleAvatar( + radius: radius, + backgroundColor: backgroundColor, + backgroundImage: image, + ), + progressIndicatorBuilder: (_, __, downloadProgress) { + final size = Size.fromRadius(radius); + + return SizedBox( + height: size.height, + width: size.width, + child: CircularProgressIndicator( + value: downloadProgress.progress, + strokeWidth: 1, + ), + ); + }, + errorWidget: (_, __, ___) => _defaultUserIcon, + ) + : _defaultUserIcon; String get _initials { String initials = ''; @@ -97,8 +108,8 @@ class DSUserAvatar extends StatelessWidget { : CircleAvatar( radius: radius, backgroundColor: backgroundColor, - backgroundImage: const AssetImage( - 'assets/images/avatar-default.png', + child: DSSvg.asset( + 'assets/svg/avatar-default.svg', package: DSUtils.packageName, ), ); diff --git a/lib/src/widgets/utils/reply_content/ds_json_reply_content.widget.dart b/lib/src/widgets/utils/reply_content/ds_json_reply_content.widget.dart new file mode 100644 index 00000000..1161dd21 --- /dev/null +++ b/lib/src/widgets/utils/reply_content/ds_json_reply_content.widget.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; + +import '../../../enums/ds_align.enum.dart'; +import '../../../models/ds_active_message.model.dart'; +import '../../../models/ds_message_bubble_style.model.dart'; +import '../../../themes/colors/ds_colors.theme.dart'; +import '../../../utils/ds_message_content_type.util.dart'; +import '../../chat/reply/ds_in_reply_content.widget.dart'; +import '../../texts/ds_body_text.widget.dart'; +import '../../texts/ds_caption_text.widget.dart'; +import '../ds_active_message_reply_content.widget.dart'; + +class DSJsonReplyContent extends StatelessWidget { + DSJsonReplyContent({ + super.key, + required this.align, + this.type, + this.content, + this.simpleStyle = false, + this.isPreview = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final DSAlign align; + final String? type; + final dynamic content; + final bool simpleStyle; + final bool isPreview; + final DSMessageBubbleStyle style; + + Color get _foregroundColor => style.isLightBubbleBackground(align) + ? const Color.fromARGB(255, 39, 4, 4) + : DSColors.surface1; + + bool get isActiveMessageReply => + type == DSMessageContentType.applicationJson && + content['type'] == 'template'; + + @override + Widget build(BuildContext context) { + late Widget child; + + if (isActiveMessageReply) { + child = DSActiveMessageContentReply( + activeMessage: DSActiveMessage.fromJson(content), + align: align, + simpleStyle: simpleStyle, + isPreview: isPreview, + style: style, + ); + } else { + child = DSInReplyContent( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (content['interactive']['body']?['text'] != null) + DSBodyText( + content['interactive']['body']?['text'], + color: _foregroundColor, + overflow: TextOverflow.visible, + ), + if (content['interactive']['footer']?['text'] != null) + DSCaptionText( + content['interactive']['footer']?['text'], + fontStyle: FontStyle.italic, + overflow: TextOverflow.visible, + color: _foregroundColor, + ), + ], + ), + ); + } + + return child; + } +} diff --git a/lib/src/widgets/utils/reply_content/ds_location_reply_content.widget.dart b/lib/src/widgets/utils/reply_content/ds_location_reply_content.widget.dart new file mode 100644 index 00000000..2f9204d3 --- /dev/null +++ b/lib/src/widgets/utils/reply_content/ds_location_reply_content.widget.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; + +import '../../../enums/ds_align.enum.dart'; +import '../../../models/ds_location.model.dart'; +import '../../../models/ds_message_bubble_style.model.dart'; +import '../../../services/ds_auth.service.dart'; +import '../../../themes/colors/ds_colors.theme.dart'; +import '../../../themes/icons/ds_icons.dart'; +import '../../animations/ds_spinner_loading.widget.dart'; +import '../../chat/reply/ds_in_reply_content.widget.dart'; +import '../../texts/ds_body_text.widget.dart'; +import '../../texts/ds_caption_text.widget.dart'; +import '../ds_cached_network_image_view.widget.dart'; + +class DSLocationReplyContent extends StatelessWidget { + DSLocationReplyContent({ + super.key, + required this.location, + required this.align, + this.simpleStyle = false, + this.isPreview = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final DSLocation location; + final DSAlign align; + final bool simpleStyle; + final bool isPreview; + final DSMessageBubbleStyle style; + + bool get hasValidCoordinates => + location.latitude != null && location.longitude != null; + + double get size => isPreview ? 50.0 : 65.0; + + Color get foregroundColor => style.isLightBubbleBackground(align) + ? const Color.fromARGB(255, 39, 4, 4) + : DSColors.surface1; + + Widget _buildThumbnail() => DSCachedNetworkImageView( + width: size, + height: size, + url: + 'https://maps.googleapis.com/maps/api/staticmap?&size=360x360&markers=${location.latitude},${location.longitude}&key=${DSAuthService.googleKey}', + placeholder: (_, __) => _buildLoading(), + align: align, + style: style, + ); + + Widget _buildBrokenThumbnail() => SizedBox( + width: size, + height: size, + child: Icon( + DSIcons.file_image_broken_outline, + size: 80, + color: style.isLightBubbleBackground(align) + ? DSColors.neutralMediumElephant + : DSColors.neutralMediumCloud, + ), + ); + + Widget _buildLoading() => Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + ), + child: Center( + child: DSSpinnerLoading( + color: style.isLightBubbleBackground(align) + ? DSColors.primaryNight + : DSColors.neutralLightSnow, + size: isPreview ? 26.0 : 32.0, + lineWidth: isPreview ? 2.0 : 4.0, + ), + ), + ), + ], + ); + + @override + Widget build(BuildContext context) { + return DSInReplyContent( + leading: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Icon( + DSIcons.localization_outline, + color: foregroundColor, + size: isPreview ? 18.0 : 24.0, + ), + ), + trailing: ClipRRect( + borderRadius: BorderRadius.circular( + 4.0, + ), + child: + hasValidCoordinates ? _buildThumbnail() : _buildBrokenThumbnail(), + ), + child: isPreview + ? DSCaptionText( + location.text, + color: foregroundColor, + ) + : DSBodyText( + location.text, + color: foregroundColor, + maxLines: 2, + ), + ); + } +} diff --git a/lib/src/widgets/utils/reply_content/ds_media_reply_content.widget.dart b/lib/src/widgets/utils/reply_content/ds_media_reply_content.widget.dart new file mode 100644 index 00000000..7fdc606f --- /dev/null +++ b/lib/src/widgets/utils/reply_content/ds_media_reply_content.widget.dart @@ -0,0 +1,219 @@ +import 'package:flutter/material.dart'; + +import '../../../enums/ds_align.enum.dart'; +import '../../../extensions/ds_localization.extension.dart'; +import '../../../models/ds_media_link.model.dart'; +import '../../../models/ds_media_reply_content_props.model.dart'; +import '../../../models/ds_message_bubble_style.model.dart'; +import '../../../services/ds_file.service.dart'; +import '../../../themes/colors/ds_colors.theme.dart'; +import '../../../themes/icons/ds_icons.dart'; +import '../../animations/ds_spinner_loading.widget.dart'; +import '../../chat/reply/ds_in_reply_content.widget.dart'; +import '../../texts/ds_body_text.widget.dart'; +import '../../texts/ds_caption_text.widget.dart'; +import '../ds_audio_duration_view.widget.dart'; +import '../ds_cached_network_image_view.widget.dart'; +import '../ds_cached_video_thumbnail_view.widget.dart'; +import '../ds_file_extension_icon.util.dart'; + +class DSMediaReplyContent extends StatelessWidget { + DSMediaReplyContent({ + super.key, + required this.media, + required this.align, + required this.shouldAuthenticate, + this.isPreview = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final DSMediaLink media; + final DSAlign align; + final bool shouldAuthenticate; + final bool isPreview; + final DSMessageBubbleStyle style; + + late final _foregroundColor = style.isLightBubbleBackground(align) + ? const Color.fromARGB(255, 39, 4, 4) + : DSColors.surface1; + + @override + Widget build(BuildContext context) { + final props = _buildReplyContent(); + + return DSInReplyContent( + leading: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Icon( + props.mediaIcon, + color: _foregroundColor, + size: isPreview ? 18.0 : 24.0, + ), + ), + trailing: props.trailing, + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 4.0, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + isPreview + ? DSCaptionText( + props.title, + color: _foregroundColor, + height: 1.0, + ) + : DSBodyText( + props.title, + color: _foregroundColor, + overflow: TextOverflow.ellipsis, + maxLines: 2, + height: 1.0, + ), + if (props.subtitle != null) props.subtitle!, + ], + ), + ); + } + + DSMediaReplyContentProps _buildReplyContent() { + bool containsType(String type) => media.type.contains(type); + + late final String mediaTextTranslateKey; + late final DSMediaReplyContentProps props; + + if (containsType('audio')) { + mediaTextTranslateKey = 'media.audio.text'; + props = _buildAudioContent(); + } else if (containsType('video')) { + mediaTextTranslateKey = 'media.video.text'; + props = _buildVideoContent(); + } else if (containsType('image')) { + mediaTextTranslateKey = 'media.image.text'; + props = _buildImageContent(); + } else { + mediaTextTranslateKey = 'media.document.text'; + props = _buildDocumentContent(); + } + + final mediaText = (media.text?.isNotEmpty ?? false) + ? media.text + : mediaTextTranslateKey.translate(); + + props.title = mediaText; + + return props; + } + + DSMediaReplyContentProps _buildAudioContent() { + final mediaTextTranslateKey = 'media.audio.text'; + final mediaIcon = DSIcons.audio_outline; + final subtitle = DSAudioDurationView( + media: media, + foreground: _foregroundColor, + ); + + return DSMediaReplyContentProps( + mediaTextTranslateKey: mediaTextTranslateKey, + mediaIcon: mediaIcon, + subtitle: subtitle, + ); + } + + DSMediaReplyContentProps _buildVideoContent() { + final size = isPreview ? 50.0 : 70.0; + final mediaTextTranslateKey = 'media.video.text'; + final mediaIcon = DSIcons.video_outline; + final trailing = _buildRoundedMedia( + DSCachedVideoThumbnailView( + url: media.uri, + width: size, + height: size, + fit: BoxFit.cover, + shouldAuthenticate: shouldAuthenticate, + style: style, + align: align, + mediaSize: media.size ?? 0, + type: media.type, + placeholder: _buildLoadingPlaceholder, + ), + ); + + return DSMediaReplyContentProps( + mediaTextTranslateKey: mediaTextTranslateKey, + mediaIcon: mediaIcon, + trailing: trailing, + size: size, + ); + } + + DSMediaReplyContentProps _buildImageContent() { + final size = isPreview ? 50.0 : 65.0; + final mediaTextTranslateKey = 'media.image.text'; + final mediaIcon = DSIcons.file_image_outline; + + final trailing = _buildRoundedMedia( + DSCachedNetworkImageView( + fit: BoxFit.cover, + width: size, + height: size, + url: media.uri, + align: align, + style: style, + shouldAuthenticate: shouldAuthenticate, + placeholder: _buildLoadingPlaceholder, + ), + ); + + return DSMediaReplyContentProps( + mediaTextTranslateKey: mediaTextTranslateKey, + mediaIcon: mediaIcon, + trailing: trailing, + size: size, + ); + } + + DSMediaReplyContentProps _buildDocumentContent() { + final size = isPreview ? 35.0 : 40.0; + final mediaTextTranslateKey = 'media.document.text'; + final mediaIcon = DSIcons.file_empty_file_outline; + + final trailing = Padding( + padding: const EdgeInsets.all(4.0), + child: DSFileExtensionIcon( + filename: media.title ?? + '${media.uri.hashCode}.${DSFileService.getExtensionFromMimeType(media.type)}', + size: size, + ), + ); + + return DSMediaReplyContentProps( + mediaTextTranslateKey: mediaTextTranslateKey, + mediaIcon: mediaIcon, + trailing: trailing, + size: size, + ); + } + + Widget _buildRoundedMedia(Widget child) { + if (isPreview) { + return ClipRRect( + borderRadius: BorderRadius.circular( + 4.0, + ), + child: child, + ); + } + + return child; + } + + Widget _buildLoadingPlaceholder(BuildContext _, String __) => Center( + child: DSSpinnerLoading( + color: style.isLightBubbleBackground(align) + ? DSColors.primaryNight + : DSColors.neutralLightSnow, + size: 20.0, + lineWidth: 2.0, + ), + ); +} diff --git a/lib/src/widgets/utils/reply_content/ds_plain_text_reply_content.widget.dart b/lib/src/widgets/utils/reply_content/ds_plain_text_reply_content.widget.dart new file mode 100644 index 00000000..b877d9bb --- /dev/null +++ b/lib/src/widgets/utils/reply_content/ds_plain_text_reply_content.widget.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +import '../../../enums/ds_align.enum.dart'; +import '../../../models/ds_message_bubble_style.model.dart'; +import '../../../themes/colors/ds_colors.theme.dart'; +import '../../chat/reply/ds_in_reply_content.widget.dart'; +import '../../texts/ds_body_text.widget.dart'; +import '../../texts/ds_caption_text.widget.dart'; +import 'ds_unsupported_reply_content.widget.dart'; + +class DSPlainTextReplyContent extends StatelessWidget { + DSPlainTextReplyContent({ + super.key, + required this.align, + required this.content, + this.isPreview = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final dynamic content; + final DSAlign align; + final bool isPreview; + final DSMessageBubbleStyle style; + + late final _foregroundColor = style.isLightBubbleBackground(align) + ? const Color.fromARGB(255, 39, 4, 4) + : DSColors.surface1; + + @override + Widget build(BuildContext context) { + return content is String + ? DSInReplyContent( + child: isPreview + ? DSCaptionText( + content.replaceAll('\n', ' '), + color: _foregroundColor, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ) + : DSBodyText( + content, + color: _foregroundColor, + overflow: TextOverflow.visible, + ), + ) + : DSUnsupportedReplyContent( + align: align, + style: style, + ); + } +} diff --git a/lib/src/widgets/utils/reply_content/ds_reply_preview.widget.dart b/lib/src/widgets/utils/reply_content/ds_reply_preview.widget.dart new file mode 100644 index 00000000..e5ef37a5 --- /dev/null +++ b/lib/src/widgets/utils/reply_content/ds_reply_preview.widget.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; + +import '../../../enums/ds_align.enum.dart'; +import '../../../models/ds_location.model.dart'; +import '../../../models/ds_media_link.model.dart'; +import '../../../models/ds_message_bubble_style.model.dart'; +import '../../../utils/ds_message_content_type.util.dart'; +import 'ds_json_reply_content.widget.dart'; +import 'ds_location_reply_content.widget.dart'; +import 'ds_media_reply_content.widget.dart'; +import 'ds_plain_text_reply_content.widget.dart'; +import 'ds_select_reply_content.widget.dart'; +import 'ds_unsupported_reply_content.widget.dart'; + +class DSReplyPreview extends StatelessWidget { + DSReplyPreview({ + super.key, + required this.align, + this.type, + this.content, + this.simpleStyle = false, + this.isPreview = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final DSAlign align; + final String? type; + final dynamic content; + final bool simpleStyle; + final bool isPreview; + final DSMessageBubbleStyle style; + + @override + Widget build(BuildContext context) { + return switch (type) { + DSMessageContentType.textPlain => _buildTextPlain(), + DSMessageContentType.select => _buidSelect(), + DSMessageContentType.mediaLink => _buildMediaLink(), + DSMessageContentType.applicationJson => _buildApplicationJson(), + DSMessageContentType.location => _buidLocation(), + _ => _buildDefault(), + }; + } + + Widget _buildTextPlain() => DSPlainTextReplyContent( + align: align, + content: content, + isPreview: isPreview, + style: style, + ); + + Widget _buidSelect() => DSSelectReplyContent( + align: align, + content: content['text'], + isPreview: isPreview, + style: style, + ); + + Widget _buildApplicationJson() => DSJsonReplyContent( + align: align, + type: type, + content: content, + simpleStyle: simpleStyle, + isPreview: isPreview, + style: style, + ); + + Widget _buildMediaLink() => DSMediaReplyContent( + align: align, + media: DSMediaLink.fromJson(content), + style: style, + isPreview: isPreview, + shouldAuthenticate: false, + ); + + Widget _buidLocation() => DSLocationReplyContent( + align: align, + location: DSLocation.fromJson(content), + simpleStyle: simpleStyle, + isPreview: isPreview, + style: style, + ); + + Widget _buildDefault() => DSUnsupportedReplyContent( + align: align, + style: style, + ); +} diff --git a/lib/src/widgets/utils/reply_content/ds_select_reply_content.widget.dart b/lib/src/widgets/utils/reply_content/ds_select_reply_content.widget.dart new file mode 100644 index 00000000..067204a7 --- /dev/null +++ b/lib/src/widgets/utils/reply_content/ds_select_reply_content.widget.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +import '../../../enums/ds_align.enum.dart'; +import '../../../models/ds_message_bubble_style.model.dart'; +import '../../../themes/colors/ds_colors.theme.dart'; +import '../../chat/reply/ds_in_reply_content.widget.dart'; +import '../../texts/ds_body_text.widget.dart'; +import '../../texts/ds_caption_text.widget.dart'; + +class DSSelectReplyContent extends StatelessWidget { + DSSelectReplyContent({ + super.key, + required this.align, + this.content, + this.isPreview = false, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final DSAlign align; + final String? content; + final bool isPreview; + final DSMessageBubbleStyle style; + + Color get _foregroundColor => style.isLightBubbleBackground(align) + ? const Color.fromARGB(255, 39, 4, 4) + : DSColors.surface1; + + @override + Widget build(BuildContext context) { + return DSInReplyContent( + child: isPreview + ? DSCaptionText( + content ?? '', + color: _foregroundColor, + ) + : DSBodyText( + content ?? '', + color: _foregroundColor, + overflow: TextOverflow.visible, + ), + ); + } +} diff --git a/lib/src/widgets/utils/reply_content/ds_unsupported_reply_content.widget.dart b/lib/src/widgets/utils/reply_content/ds_unsupported_reply_content.widget.dart new file mode 100644 index 00000000..5599acd7 --- /dev/null +++ b/lib/src/widgets/utils/reply_content/ds_unsupported_reply_content.widget.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; + +import '../../../enums/ds_align.enum.dart'; +import '../../../extensions/ds_localization.extension.dart'; +import '../../../models/ds_message_bubble_style.model.dart'; +import '../../../themes/colors/ds_colors.theme.dart'; +import '../../../themes/icons/ds_icons.dart'; +import '../../chat/reply/ds_in_reply_content.widget.dart'; +import '../../texts/ds_body_text.widget.dart'; + +class DSUnsupportedReplyContent extends StatelessWidget { + DSUnsupportedReplyContent({ + super.key, + this.align = DSAlign.right, + DSMessageBubbleStyle? style, + }) : style = style ?? DSMessageBubbleStyle(); + + final DSAlign align; + final DSMessageBubbleStyle style; + + late final _foregroundColor = style.isLightBubbleBackground(align) + ? const Color.fromARGB(255, 39, 4, 4) + : DSColors.surface1; + + @override + Widget build(BuildContext context) { + return DSInReplyContent( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + DSIcons.warning_outline, + color: _foregroundColor, + size: 24.0, + ), + const SizedBox(width: 8.0), + Flexible( + child: DSBodyText( + 'reply.load-fail'.translate(), + overflow: TextOverflow.visible, + color: _foregroundColor, + ), + ), + ], + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 0d787c49..d7826f83 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,15 +5,14 @@ homepage: https://github.com/takenet/blip-ds-flutter#readme repository: https://github.com/takenet/blip-ds-flutter environment: - sdk: ">=3.0.5 <4.0.0" - flutter: ">=1.17.0" + sdk: ^3.5.3 dependencies: flutter: sdk: flutter ffmpeg_kit_flutter_full_gpl: ^6.0.3 just_audio: ^0.9.35 - rxdart: ^0.27.4 + rxdart: ^0.27.7 flutter_spinkit: ^5.1.0 get: ^4.6.5 open_filex: ^4.5.0 @@ -36,7 +35,7 @@ dependencies: mask_text_input_formatter: ^2.4.0 dotted_border: ^2.0.0+3 map_launcher: ^3.1.0 - mime: ^1.0.4 + mime: ^2.0.0 crypto: ^3.0.3 video_compress: ^3.1.3 flutter_image_compress: ^2.1.0 @@ -46,15 +45,16 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^3.0.1 + flutter_lints: ^5.0.0 golden_toolkit: ^0.15.0 flutter: uses-material-design: true - + assets: - assets/images/ - assets/svg/flags/ + - assets/svg/ fonts: - family: NunitoSans diff --git a/sample/lib/controllers/sample_group_card.controller.dart b/sample/lib/controllers/sample_group_card.controller.dart index 57514571..c232e884 100644 --- a/sample/lib/controllers/sample_group_card.controller.dart +++ b/sample/lib/controllers/sample_group_card.controller.dart @@ -2,11 +2,10 @@ import 'dart:convert'; import 'package:blip_ds/blip_ds.dart'; import 'package:flutter/material.dart'; -import 'package:get/get.dart'; class SampleGroupCardController { Future> getMessages() async { - String data = await DefaultAssetBundle.of(Get.context!) + String data = await DefaultAssetBundle.of(DSContextService.context!) .loadString("assets/messages.json"); final jsonResult = jsonDecode(data); diff --git a/sample/pubspec.lock b/sample/pubspec.lock index c3c4b0a5..f3df7716 100644 --- a/sample/pubspec.lock +++ b/sample/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.6.0" async: dependency: transitive description: @@ -21,17 +21,17 @@ packages: dependency: transitive description: name: audio_session - sha256: "6fdf255ed3af86535c96452c33ecff1245990bb25a605bfb1958661ccc3d467f" + sha256: "343e83bc7809fbda2591a49e525d6b63213ade10c76f15813be9aed6657b3261" url: "https://pub.dev" source: hosted - version: "0.1.18" + version: "0.1.21" blip_ds: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.2.5" + version: "0.2.6" boolean_selector: dependency: transitive description: @@ -44,26 +44,26 @@ packages: dependency: transitive description: name: cached_network_image - sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.1" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.3.1" characters: dependency: transitive description: @@ -76,18 +76,18 @@ packages: dependency: transitive description: name: charcode - sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" chewie: dependency: transitive description: name: chewie - sha256: "8bc4ac4cf3f316e50a25958c0f5eb9bb12cf7e8308bb1d74a43b230da2cfc144" + sha256: "335df378c025588aef400c704bd71f0daea479d4cd57c471c88c056c1144e7cd" url: "https://pub.dev" source: hosted - version: "1.7.5" + version: "1.8.5" clock: dependency: transitive description: @@ -100,42 +100,42 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.19.0" cross_file: dependency: transitive description: name: cross_file - sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5" + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted - version: "0.3.3+7" + version: "0.3.4+2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" csslib: dependency: transitive description: name: csslib - sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "1.0.8" dbus: dependency: transitive description: @@ -156,10 +156,18 @@ packages: dependency: transitive description: name: dio - sha256: "50fec96118958b97c727d0d8f67255d3683f16cc1f90d9bc917b5d4fe3abeca9" + sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" url: "https://pub.dev" source: hosted - version: "5.4.2" + version: "5.7.0" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" + url: "https://pub.dev" + source: hosted + version: "2.0.0" dotted_border: dependency: transitive description: @@ -180,10 +188,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.3" ffmpeg_kit_flutter_full_gpl: dependency: transitive description: @@ -204,10 +212,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" file_sizes: dependency: transitive description: @@ -216,6 +224,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.6" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -225,50 +241,58 @@ packages: dependency: transitive description: name: flutter_cache_manager - sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.1" flutter_image_compress: dependency: transitive description: name: flutter_image_compress - sha256: f159d2e8c4ed04b8e36994124fd4a5017a0f01e831ae3358c74095c340e9ae5e + sha256: "45a3071868092a61b11044c70422b04d39d4d9f2ef536f3c5b11fb65a1e7dd90" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.0" flutter_image_compress_common: dependency: transitive description: name: flutter_image_compress_common - sha256: "7cad12802628706655920089cfe9ee1d1098300e7f39a079eb160458bbc47652" + sha256: "7f79bc6c8a363063620b4e372fa86bc691e1cb28e58048cd38e030692fbd99ee" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.5" flutter_image_compress_macos: dependency: transitive description: name: flutter_image_compress_macos - sha256: fea1e3d71150d03373916b832c49b5c2f56c3e7e13da82a929274a2c6f88251e + sha256: "26df6385512e92b3789dc76b613b54b55c457a7f1532e59078b04bf189782d47" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" + flutter_image_compress_ohos: + dependency: transitive + description: + name: flutter_image_compress_ohos + sha256: e76b92bbc830ee08f5b05962fc78a532011fcd2041f620b5400a593e96da3f51 + url: "https://pub.dev" + source: hosted + version: "0.0.3" flutter_image_compress_platform_interface: dependency: transitive description: name: flutter_image_compress_platform_interface - sha256: eb4f055138b29b04498ebcb6d569aaaee34b64d75fb74ea0d40f9790bf47ee9d + sha256: "579cb3947fd4309103afe6442a01ca01e1e6f93dc53bb4cbd090e8ce34a41889" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.5" flutter_image_compress_web: dependency: transitive description: name: flutter_image_compress_web - sha256: da41cc3859f19d11c7d10be615f6a9dcf0907e7daffde7442bf4cc2486663660 + sha256: f02fe352b17f82b72f481de45add240db062a2585850bea1667e82cc4cd6c311 url: "https://pub.dev" source: hosted - version: "0.1.3+2" + version: "0.1.4+1" flutter_lints: dependency: "direct dev" description: @@ -289,18 +313,18 @@ packages: dependency: transitive description: name: flutter_spinkit - sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e + sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.2.1" flutter_svg: dependency: transitive description: name: flutter_svg - sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c + sha256: "54900a1a1243f3c4a5506d853a2b5c2dbc38d5f27e52a52618a8054401431123" url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.16" flutter_test: dependency: "direct dev" description: flutter @@ -323,58 +347,82 @@ packages: dependency: transitive description: name: html - sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" url: "https://pub.dev" source: hosted - version: "0.15.4" + version: "0.15.5" http: dependency: transitive description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.2" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.1" js: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.7.1" just_audio: dependency: transitive description: name: just_audio - sha256: b607cd1a43bac03d85c3aaee00448ff4a589ef2a77104e3d409889ff079bf823 + sha256: a49e7120b95600bd357f37a2bb04cd1e88252f7cdea8f3368803779b925b1049 url: "https://pub.dev" source: hosted - version: "0.9.36" + version: "0.9.42" just_audio_platform_interface: dependency: transitive description: name: just_audio_platform_interface - sha256: c3dee0014248c97c91fe6299edb73dc4d6c6930a2f4f713579cd692d9e47f4a1 + sha256: "0243828cce503c8366cc2090cefb2b3c871aa8ed2f520670d76fd47aa1ab2790" url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.3.0" just_audio_web: dependency: transitive description: name: just_audio_web - sha256: "134356b0fe3d898293102b33b5fd618831ffdc72bb7a1b726140abdf22772b70" + sha256: "9a98035b8b24b40749507687520ec5ab404e291d2b0937823ff45d92cb18d448" url: "https://pub.dev" source: hosted - version: "0.4.9" + version: "0.4.13" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + url: "https://pub.dev" + source: hosted + version: "10.0.7" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + url: "https://pub.dev" + source: hosted + version: "3.0.8" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" linkify: dependency: transitive description: @@ -395,10 +443,10 @@ packages: dependency: transitive description: name: map_launcher - sha256: b9c11a1d32740ef8393559148716cc0fec38a569fdcf3fb569375114cf30988a + sha256: "7436d6ef9ae57ff15beafcedafe0a8f0604006cbecd2d26024c4cfb0158c2b9a" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.5.0" mask_text_input_formatter: dependency: transitive description: @@ -411,26 +459,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.15.0" metadata_fetch_plus: dependency: transitive description: @@ -443,10 +491,10 @@ packages: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" nested: dependency: transitive description: @@ -459,10 +507,10 @@ packages: dependency: transitive description: name: octo_image - sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.0" open_filex: dependency: transitive description: @@ -475,26 +523,26 @@ packages: dependency: transitive description: name: package_info_plus - sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017" + sha256: "70c421fe9d9cc1a9a7f3b05ae56befd469fe4f8daa3b484823141a55442d858d" url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "8.1.2" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + sha256: a5ef9986efc7bf772f2696183a3992615baa76c1ffb1189318dd8803778fb05b url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.2" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_drawing: dependency: transitive description: @@ -507,34 +555,34 @@ packages: dependency: transitive description: name: path_parsing - sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" path_provider: dependency: transitive description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.15" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -555,18 +603,18 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: name: petitparser - sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "6.0.2" phone_number: dependency: transitive description: @@ -587,10 +635,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -603,18 +651,18 @@ packages: dependency: transitive description: name: pointer_interceptor - sha256: bd18321519718678d5fa98ad3a3359cbc7a31f018554eab80b73d08a7f0c165a + sha256: "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523" url: "https://pub.dev" source: hosted - version: "0.10.1" + version: "0.10.1+2" pointer_interceptor_ios: dependency: transitive description: name: pointer_interceptor_ios - sha256: "2e73c39452830adc4695757130676a39412a3b7f3c34e3f752791b5384770877" + sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917 url: "https://pub.dev" source: hosted - version: "0.10.0+2" + version: "0.10.1" pointer_interceptor_platform_interface: dependency: transitive description: @@ -627,10 +675,10 @@ packages: dependency: transitive description: name: pointer_interceptor_web - sha256: "2a8a069206f7b234a895d30ccab8b18ea267eeb79a832e5e3d1b6464d659eb6a" + sha256: "7a7087782110f8c1827170660b09f8aa893e0e9a61431dbbe2ac3fc482e8c044" url: "https://pub.dev" source: hosted - version: "0.10.0" + version: "0.10.2+1" provider: dependency: transitive description: @@ -647,14 +695,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + scroll_to_index: + dependency: transitive + description: + name: scroll_to_index + sha256: b707546e7500d9f070d63e5acf74fd437ec7eeeb68d3412ef7b0afada0b4f176 + url: "https://pub.dev" + source: hosted + version: "3.0.1" simple_animations: dependency: transitive description: name: simple_animations - sha256: "1ea7b93fb98e2a611b6865d632de55607b766328d14700143353129ee0559d3a" + sha256: "6c0f1d53d351a2187da979cc6883322eb9e76f1147c1aecc1937c498eaa9abff" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "5.1.0" simple_link_preview: dependency: transitive description: @@ -675,7 +731,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -696,26 +752,50 @@ packages: dependency: transitive description: name: sqflite - sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" + url: "https://pub.dev" + source: hosted + version: "2.4.0" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.5.4+6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" sticky_headers: dependency: transitive description: @@ -728,34 +808,34 @@ packages: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" string_validator: dependency: transitive description: name: string_validator - sha256: "54d4f42cd6878ae72793a58a529d9a18ebfdfbfebd9793bbe55c9b28935e8543" + sha256: a278d038104aa2df15d0e09c47cb39a49f907260732067d0034dc2f2e4e2ac94 url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" synchronized: dependency: transitive description: name: synchronized - sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" url: "https://pub.dev" source: hosted - version: "3.1.0+1" + version: "3.3.0+3" term_glyph: dependency: transitive description: @@ -768,18 +848,18 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.7.3" typed_data: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" universal_html: dependency: transitive description: @@ -800,42 +880,42 @@ packages: dependency: transitive description: name: url_launcher - sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.1" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.14" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.2" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -848,50 +928,50 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 + sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.3" uuid: dependency: transitive description: name: uuid - sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.5.1" vector_graphics: dependency: transitive description: name: vector_graphics - sha256: "4ac59808bbfca6da38c99f415ff2d3a5d7ca0a6b4809c71d9cf30fba5daf9752" + sha256: "27d5fefe86fb9aace4a9f8375b56b3c292b64d8c04510df230f849850d912cb7" url: "https://pub.dev" source: hosted - version: "1.1.10+1" + version: "1.1.15" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: f3247e7ab0ec77dc759263e68394990edc608fb2b480b80db8aa86ed09279e33 + sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb" url: "https://pub.dev" source: hosted - version: "1.1.10+1" + version: "1.1.12" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "18489bdd8850de3dd7ca8a34e0c446f719ec63e2bab2e7a8cc66a9028dd76c5a" + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" url: "https://pub.dev" source: hosted - version: "1.1.10+1" + version: "1.1.16" vector_math: dependency: transitive description: @@ -912,90 +992,98 @@ packages: dependency: transitive description: name: video_player - sha256: fbf28ce8bcfe709ad91b5789166c832cb7a684d14f571a81891858fefb5bb1c2 + sha256: "4a8c3492d734f7c39c2588a3206707a05ee80cef52e8c7f3b2078d430c84bc17" url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.9.2" video_player_android: dependency: transitive description: name: video_player_android - sha256: "4dd9b8b86d70d65eecf3dcabfcdfbb9c9115d244d022654aba49a00336d540c2" + sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898" url: "https://pub.dev" source: hosted - version: "2.4.12" + version: "2.7.16" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: bc923884640d6dc403050586eb40713cdb8d1d84e6886d8aca50ab04c59124c2 + sha256: "33224c19775fd244be2d6e3dbd8e1826ab162877bd61123bf71890772119a2b7" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.6.5" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" + sha256: "229d7642ccd9f3dc4aba169609dd6b5f3f443bb4cc15b82f7785fcada5af9bbb" url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.2.3" video_player_web: dependency: transitive description: name: video_player_web - sha256: "34beb3a07d4331a24f7e7b2f75b8e2b103289038e07e65529699a671b6a6e2cb" + sha256: "881b375a934d8ebf868c7fb1423b2bfaa393a0a265fa3f733079a86536064a10" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.3" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + url: "https://pub.dev" + source: hosted + version: "14.3.0" wakelock_plus: dependency: transitive description: name: wakelock_plus - sha256: f268ca2116db22e57577fb99d52515a24bdc1d570f12ac18bb762361d43b043d + sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 url: "https://pub.dev" source: hosted - version: "1.1.4" + version: "1.2.8" wakelock_plus_platform_interface: dependency: transitive description: name: wakelock_plus_platform_interface - sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385" + sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.1" web: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "1.1.0" win32: dependency: transitive description: name: win32 - sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 + sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.9.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" xml: dependency: transitive description: name: xml - sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.5.0" sdks: - dart: ">=3.1.0 <4.0.0" - flutter: ">=3.13.0" + dart: ">=3.5.4 <4.0.0" + flutter: ">=3.24.0" diff --git a/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_0.png b/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_0.png index d8a39de7..3f44a810 100644 Binary files a/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_0.png and b/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_0.png differ diff --git a/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_1.png b/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_1.png index a3ef636c..91c57a75 100644 Binary files a/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_1.png and b/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_1.png differ diff --git a/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_2.png b/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_2.png index fcf80708..6c80c6fb 100644 Binary files a/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_2.png and b/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_2.png differ diff --git a/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_3.png b/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_3.png index b6615f63..91f77a4c 100644 Binary files a/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_3.png and b/test/widgets/animations/goldens/ds_animated_size/ds_animated_size_step_3.png differ diff --git a/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_0.png b/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_0.png index 3599118e..953ca8d4 100644 Binary files a/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_0.png and b/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_0.png differ diff --git a/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_1.png b/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_1.png index 07706a68..f512b639 100644 Binary files a/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_1.png and b/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_1.png differ diff --git a/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_2.png b/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_2.png index fff11a0f..70c4193c 100644 Binary files a/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_2.png and b/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_2.png differ diff --git a/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_3.png b/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_3.png index 824a4147..c6daccfe 100644 Binary files a/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_3.png and b/test/widgets/animations/goldens/ds_ring_loading/ds_ring_loading_step_3.png differ diff --git a/test/widgets/buttons/goldens/ds_button/disabled/ds_button_disabled.png b/test/widgets/buttons/goldens/ds_button/disabled/ds_button_disabled.png index aac2e405..4c0b4e69 100644 Binary files a/test/widgets/buttons/goldens/ds_button/disabled/ds_button_disabled.png and b/test/widgets/buttons/goldens/ds_button/disabled/ds_button_disabled.png differ diff --git a/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_0.png b/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_0.png index 175e3be2..a5d9bcee 100644 Binary files a/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_0.png and b/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_0.png differ diff --git a/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_1.png b/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_1.png index 934878e4..8f15bfc2 100644 Binary files a/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_1.png and b/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_1.png differ diff --git a/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_2.png b/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_2.png index 05b365c9..f4b18b89 100644 Binary files a/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_2.png and b/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_2.png differ diff --git a/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_3.png b/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_3.png index f2896a3a..0fdd576d 100644 Binary files a/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_3.png and b/test/widgets/buttons/goldens/ds_button/disabled/loading/ds_button_disabled_loading_step_3.png differ diff --git a/test/widgets/buttons/goldens/ds_button/enabled/ds_button_enabled.png b/test/widgets/buttons/goldens/ds_button/enabled/ds_button_enabled.png index 372e4f73..00a1b080 100644 Binary files a/test/widgets/buttons/goldens/ds_button/enabled/ds_button_enabled.png and b/test/widgets/buttons/goldens/ds_button/enabled/ds_button_enabled.png differ diff --git a/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_0.png b/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_0.png index 6083aadd..0b3adf0b 100644 Binary files a/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_0.png and b/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_0.png differ diff --git a/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_1.png b/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_1.png index 0665a651..fd5ffd8d 100644 Binary files a/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_1.png and b/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_1.png differ diff --git a/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_2.png b/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_2.png index 74afff19..26c7b3c1 100644 Binary files a/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_2.png and b/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_2.png differ diff --git a/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_3.png b/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_3.png index 47a91c87..59168f55 100644 Binary files a/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_3.png and b/test/widgets/buttons/goldens/ds_button/enabled/loading/ds_button_enabled_loading_step_3.png differ diff --git a/test/widgets/buttons/goldens/ds_pause_button/ds_pause_button.png b/test/widgets/buttons/goldens/ds_pause_button/ds_pause_button.png index a18b171c..d7b13779 100644 Binary files a/test/widgets/buttons/goldens/ds_pause_button/ds_pause_button.png and b/test/widgets/buttons/goldens/ds_pause_button/ds_pause_button.png differ diff --git a/test/widgets/buttons/goldens/ds_play_button/ds_play_button.png b/test/widgets/buttons/goldens/ds_play_button/ds_play_button.png index b354bb92..92758cce 100644 Binary files a/test/widgets/buttons/goldens/ds_play_button/ds_play_button.png and b/test/widgets/buttons/goldens/ds_play_button/ds_play_button.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/disabled/ds_primary_button_disabled.png b/test/widgets/buttons/goldens/ds_primary_button/disabled/ds_primary_button_disabled.png index eaafb87c..55ab4f17 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/disabled/ds_primary_button_disabled.png and b/test/widgets/buttons/goldens/ds_primary_button/disabled/ds_primary_button_disabled.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_0.png b/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_0.png index 81ac9107..89b1752c 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_0.png and b/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_0.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_1.png b/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_1.png index ab382a20..adb888f6 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_1.png and b/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_1.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_2.png b/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_2.png index 7dfcfe0e..733e98e8 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_2.png and b/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_2.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_3.png b/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_3.png index 98ede715..3745bcec 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_3.png and b/test/widgets/buttons/goldens/ds_primary_button/disabled/loading/ds_primary_button_disabled_loading_step_3.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/enabled/ds_primary_button_enabled.png b/test/widgets/buttons/goldens/ds_primary_button/enabled/ds_primary_button_enabled.png index 95e58d31..037d7eb4 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/enabled/ds_primary_button_enabled.png and b/test/widgets/buttons/goldens/ds_primary_button/enabled/ds_primary_button_enabled.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_0.png b/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_0.png index 713be5e1..b622c22f 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_0.png and b/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_0.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_1.png b/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_1.png index 480ada05..bcaffed8 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_1.png and b/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_1.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_2.png b/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_2.png index 9e86812f..a63023a7 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_2.png and b/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_2.png differ diff --git a/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_3.png b/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_3.png index ac6d088f..cdc168a4 100644 Binary files a/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_3.png and b/test/widgets/buttons/goldens/ds_primary_button/enabled/loading/ds_primary_button_enabled_loading_step_3.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/disabled/ds_secondary_button_disabled.png b/test/widgets/buttons/goldens/ds_secondary_button/disabled/ds_secondary_button_disabled.png index 26cfc7ce..efd45ddd 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/disabled/ds_secondary_button_disabled.png and b/test/widgets/buttons/goldens/ds_secondary_button/disabled/ds_secondary_button_disabled.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_0.png b/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_0.png index 056f3428..03102c62 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_0.png and b/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_0.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_1.png b/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_1.png index bd0c8c6e..05aa64e1 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_1.png and b/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_1.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_2.png b/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_2.png index 2b03e5e5..1abc2fe8 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_2.png and b/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_2.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_3.png b/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_3.png index 7f9e2622..997a1f25 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_3.png and b/test/widgets/buttons/goldens/ds_secondary_button/disabled/loading/ds_secondary_button_disabled_loading_step_3.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/enabled/ds_secondary_button_enabled.png b/test/widgets/buttons/goldens/ds_secondary_button/enabled/ds_secondary_button_enabled.png index 513a52dc..cc3e8461 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/enabled/ds_secondary_button_enabled.png and b/test/widgets/buttons/goldens/ds_secondary_button/enabled/ds_secondary_button_enabled.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_0.png b/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_0.png index e9960306..d154986f 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_0.png and b/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_0.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_1.png b/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_1.png index 1897564d..1faf164a 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_1.png and b/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_1.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_2.png b/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_2.png index a9cbdc36..827a22fc 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_2.png and b/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_2.png differ diff --git a/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_3.png b/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_3.png index 2f0517ce..2eac5381 100644 Binary files a/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_3.png and b/test/widgets/buttons/goldens/ds_secondary_button/enabled/loading/ds_secondary_button_enabled_loading_step_3.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/ds_tertiary_button_disabled.png b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/ds_tertiary_button_disabled.png index 05553624..30746f28 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/ds_tertiary_button_disabled.png and b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/ds_tertiary_button_disabled.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_0.png b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_0.png index 4f277e2a..6f8d0022 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_0.png and b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_0.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_1.png b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_1.png index f679ba64..83e33ca0 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_1.png and b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_1.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_2.png b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_2.png index dc84bdc1..cbb31591 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_2.png and b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_2.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_3.png b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_3.png index 1440ef03..f155d4de 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_3.png and b/test/widgets/buttons/goldens/ds_tertiary_button/disabled/loading/ds_tertiary_button_disabled_loading_step_3.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/ds_tertiary_button_enabled.png b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/ds_tertiary_button_enabled.png index 49d53ff3..fe83858b 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/ds_tertiary_button_enabled.png and b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/ds_tertiary_button_enabled.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_0.png b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_0.png index 73c98398..dff0595a 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_0.png and b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_0.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_1.png b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_1.png index 726098ca..6b56f67e 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_1.png and b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_1.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_2.png b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_2.png index d87408fe..1ededc70 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_2.png and b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_2.png differ diff --git a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_3.png b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_3.png index f71ee41b..5f530344 100644 Binary files a/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_3.png and b/test/widgets/buttons/goldens/ds_tertiary_button/enabled/loading/ds_tertiary_button_enabled_loading_step_3.png differ diff --git a/test/widgets/chat/goldens/ds_delivery_report_icon/ds_delivery_report_icon.png b/test/widgets/chat/goldens/ds_delivery_report_icon/ds_delivery_report_icon.png index 4e766489..d8507ba3 100644 Binary files a/test/widgets/chat/goldens/ds_delivery_report_icon/ds_delivery_report_icon.png and b/test/widgets/chat/goldens/ds_delivery_report_icon/ds_delivery_report_icon.png differ