diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ea216f8..ec9632b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.2 + +- [DSLocationMessageBubble] Added app selection when touching the map preview. + ## 0.1.1 - [DSVideoMessageBubble] Added title to this bubble. 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 b4616fcf..7c52fdc7 100644 --- a/lib/src/widgets/chat/ds_location_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_location_message_bubble.widget.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:map_launcher/map_launcher.dart'; import '../../enums/ds_align.enum.dart'; @@ -6,15 +7,19 @@ import '../../enums/ds_border_radius.enum.dart'; 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 '../../themes/colors/ds_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../utils/ds_utils.util.dart'; import '../animations/ds_spinner_loading.widget.dart'; +import '../buttons/ds_icon_button.widget.dart'; import '../texts/ds_body_text.widget.dart'; +import '../texts/ds_headline_large_text.widget.dart'; import '../utils/ds_cached_network_image_view.widget.dart'; +import '../utils/ds_divider.widget.dart'; import 'ds_message_bubble.widget.dart'; -class DSLocationMessageBubble extends StatelessWidget { +class DSLocationMessageBubble extends StatefulWidget { final DSAlign align; final DSMessageBubbleStyle style; final String? title; @@ -35,81 +40,169 @@ class DSLocationMessageBubble extends StatelessWidget { }) : style = style ?? DSMessageBubbleStyle(); @override - Widget build(BuildContext context) { - final foregroundColor = style.isLightBubbleBackground(align) + State createState() => + _DSLocationMessageBubbleState(); +} + +class _DSLocationMessageBubbleState extends State { + late final Future> _installedMaps; + late final bool _hasValidCoordinates; + late final Color _foregroundColor; + late final double? _doubleLatitude; + late final double? _doubleLongitude; + + @override + void initState() { + super.initState(); + + _foregroundColor = widget.style.isLightBubbleBackground(widget.align) ? DSColors.neutralDarkCity : DSColors.neutralLightSnow; - final lat = double.tryParse(latitude); - final long = double.tryParse(longitude); - - final hasValidCoordinates = lat != null && long != null; - return GestureDetector( - onTap: () async { - final availableMaps = await MapLauncher.installedMaps; - - if (hasValidCoordinates) { - await availableMaps.first.showMarker( - coords: Coords(lat, long), - title: title ?? '', - ); - } - }, - child: DSMessageBubble( - shouldUseDefaultSize: true, - defaultMaxSize: DSUtils.bubbleMinSize, - defaultMinSize: DSUtils.bubbleMinSize, - borderRadius: borderRadius, - replyContent: replyContent, - padding: EdgeInsets.zero, - align: align, - style: style, - child: Padding( - padding: replyContent == null - ? EdgeInsets.zero - : const EdgeInsets.only(top: 8.0), + _doubleLatitude = double.tryParse(widget.latitude); + _doubleLongitude = double.tryParse(widget.longitude); + + _hasValidCoordinates = _doubleLatitude != null && _doubleLongitude != null; + + _installedMaps = MapLauncher.installedMaps; + } + + @override + Widget build(BuildContext context) => GestureDetector( + onTap: _hasValidCoordinates ? _openMapList : null, + child: DSMessageBubble( + shouldUseDefaultSize: true, + defaultMaxSize: DSUtils.bubbleMinSize, + defaultMinSize: DSUtils.bubbleMinSize, + borderRadius: widget.borderRadius, + replyContent: widget.replyContent, + padding: EdgeInsets.zero, + align: widget.align, + style: widget.style, + child: _buildBody(), + ), + ); + + Widget _buildBody() => Padding( + padding: widget.replyContent == null + ? EdgeInsets.zero + : const EdgeInsets.only(top: 8.0), + child: Center( child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, children: [ - hasValidCoordinates - ? DSCachedNetworkImageView( - url: - 'https://maps.googleapis.com/maps/api/staticmap?&size=360x360&markers=$latitude,$longitude&key=${DSAuthService.googleKey}', - placeholder: (_, __) => _buildLoading(), - align: align, - style: style, - ) - : SizedBox( - width: 240, - height: 240, - child: Icon( - DSIcons.file_image_broken_outline, - size: 80, - color: style.isLightBubbleBackground(align) - ? DSColors.neutralMediumElephant - : DSColors.neutralMediumCloud, - ), - ), - if (title?.isNotEmpty ?? false) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Align( - alignment: Alignment.topLeft, - child: DSBodyText( - title!, - color: foregroundColor, - isSelectable: true, - overflow: TextOverflow.visible, - ), - ), - ), + _hasValidCoordinates + ? _buildThumbnail() + : _buildBrokenThumbnail(), + if (widget.title?.isNotEmpty ?? false) _buildTitle(), ], ), ), + ); + + Widget _buildTitle() => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Align( + alignment: Alignment.topLeft, + child: DSBodyText( + widget.title!, + color: _foregroundColor, + isSelectable: true, + overflow: TextOverflow.visible, + ), + ), + ); + + Widget _buildThumbnail() => DSCachedNetworkImageView( + url: + 'https://maps.googleapis.com/maps/api/staticmap?&size=360x360&markers=${widget.latitude},${widget.longitude}&key=${DSAuthService.googleKey}', + placeholder: (_, __) => _buildLoading(), + align: widget.align, + style: widget.style, + ); + + Widget _buildBrokenThumbnail() => SizedBox( + width: 240, + height: 240, + child: Icon( + DSIcons.file_image_broken_outline, + size: 80, + color: widget.style.isLightBubbleBackground(widget.align) + ? DSColors.neutralMediumElephant + : DSColors.neutralMediumCloud, + ), + ); + + void _openMapList() { + DSBottomSheetService( + context: context, + fixedHeader: _buildBottomSheetHeader(), + builder: (_) => _buildBottomSheetBody(), + ).show(); + } + + Widget _buildBottomSheetHeader() { + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: SafeArea( + top: false, + bottom: false, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + DSHeadlineLargeText( + 'Selecione uma ação', + ), + DSIconButton( + onPressed: () { + Get.back(); + }, + icon: const Icon(DSIcons.close_outline, + color: DSColors.neutralDarkRooftop), + ), + ], + ), + ), + ), + const DSDivider() + ], + ); + } + + Widget _buildBottomSheetBody() { + return SafeArea( + child: FutureBuilder( + future: _installedMaps, + builder: (_, snapshot) => snapshot.hasData && snapshot.data!.isNotEmpty + ? ListView.builder( + shrinkWrap: true, + itemCount: snapshot.data!.length, + itemBuilder: (_, index) { + final map = snapshot.data![index]; + + return ListTile( + onTap: () { + map.showMarker( + coords: Coords( + _doubleLatitude!, + _doubleLongitude!, + ), + title: widget.title ?? '', + ); + + Get.back(); + }, + title: DSBodyText( + 'Abrir com ${map.mapName}', + ), + ); + }, + ) + : _buildLoading(), ), ); } @@ -123,7 +216,7 @@ class DSLocationMessageBubble extends StatelessWidget { ), child: Center( child: DSSpinnerLoading( - color: style.isLightBubbleBackground(align) + color: widget.style.isLightBubbleBackground(widget.align) ? DSColors.primaryNight : DSColors.neutralLightSnow, size: 32.0, diff --git a/pubspec.yaml b/pubspec.yaml index 9e355a7f..0a5c73b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: blip_ds description: Blip Design System for Flutter. -version: 0.1.1 +version: 0.1.2 homepage: https://github.com/takenet/blip-ds-flutter#readme repository: https://github.com/takenet/blip-ds-flutter diff --git a/sample/ios/Podfile.lock b/sample/ios/Podfile.lock index 512f2e6d..21b80eee 100644 --- a/sample/ios/Podfile.lock +++ b/sample/ios/Podfile.lock @@ -1,12 +1,12 @@ PODS: - audio_session (0.0.1): - Flutter - - ffmpeg-kit-ios-full-gpl (5.1) - - ffmpeg_kit_flutter_full_gpl (5.1.0): - - ffmpeg_kit_flutter_full_gpl/full-gpl (= 5.1.0) + - ffmpeg-kit-ios-full-gpl (6.0) + - ffmpeg_kit_flutter_full_gpl (6.0.3): + - ffmpeg_kit_flutter_full_gpl/full-gpl (= 6.0.3) - Flutter - - ffmpeg_kit_flutter_full_gpl/full-gpl (5.1.0): - - ffmpeg-kit-ios-full-gpl (= 5.1) + - ffmpeg_kit_flutter_full_gpl/full-gpl (6.0.3): + - ffmpeg-kit-ios-full-gpl (= 6.0) - Flutter - Flutter (1.0.0) - flutter_image_compress_common (1.0.0): @@ -14,9 +14,6 @@ PODS: - Mantle - SDWebImage - SDWebImageWebPCoder - - FMDB (2.7.5): - - FMDB/standard (= 2.7.5) - - FMDB/standard (2.7.5) - just_audio (0.0.1): - Flutter - libwebp (1.3.2): @@ -43,15 +40,21 @@ PODS: - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - - SDWebImage (5.18.5): - - SDWebImage/Core (= 5.18.5) - - SDWebImage/Core (5.18.5) - - SDWebImageWebPCoder (0.14.2): + - phone_number (2.0.1): + - Flutter + - PhoneNumberKit/PhoneNumberKitCore (= 3.6.6) + - PhoneNumberKit/PhoneNumberKitCore (3.6.6) + - pointer_interceptor_ios (0.0.1): + - Flutter + - SDWebImage (5.19.2): + - SDWebImage/Core (= 5.19.2) + - SDWebImage/Core (5.19.2) + - SDWebImageWebPCoder (0.14.6): - libwebp (~> 1.0) - SDWebImage/Core (~> 5.17) - sqflite (0.0.3): - Flutter - - FMDB (>= 2.7.5) + - FlutterMacOS - url_launcher_ios (0.0.1): - Flutter - video_compress (0.3.0): @@ -72,7 +75,9 @@ DEPENDENCIES: - open_filex (from `.symlinks/plugins/open_filex/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - - sqflite (from `.symlinks/plugins/sqflite/ios`) + - phone_number (from `.symlinks/plugins/phone_number/ios`) + - pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`) + - sqflite (from `.symlinks/plugins/sqflite/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_compress (from `.symlinks/plugins/video_compress/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) @@ -81,9 +86,9 @@ DEPENDENCIES: SPEC REPOS: trunk: - ffmpeg-kit-ios-full-gpl - - FMDB - libwebp - Mantle + - PhoneNumberKit - SDWebImage - SDWebImageWebPCoder @@ -106,8 +111,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" + phone_number: + :path: ".symlinks/plugins/phone_number/ios" + pointer_interceptor_ios: + :path: ".symlinks/plugins/pointer_interceptor_ios/ios" sqflite: - :path: ".symlinks/plugins/sqflite/ios" + :path: ".symlinks/plugins/sqflite/darwin" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" video_compress: @@ -119,26 +128,28 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: audio_session: 4f3e461722055d21515cf3261b64c973c062f345 - ffmpeg-kit-ios-full-gpl: 2682965e5b3e7f13a05836d46d302eafe6c5039e - ffmpeg_kit_flutter_full_gpl: 7dcfcdc419f4667252cde1871859976bca328169 + ffmpeg-kit-ios-full-gpl: 80adc341962e55ef709e36baa8ed9a70cf4ea62b + ffmpeg_kit_flutter_full_gpl: 8d15c14c0c3aba616fac04fe44b3d27d02e3c330 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e - FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d map_launcher: e325db1261d029ff33e08e03baccffe09593ffea open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4 package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 - SDWebImage: 7ac2b7ddc5e8484c79aa90fc4e30b149d6a2c88f - SDWebImageWebPCoder: 633b813fca24f1de5e076bcd7f720c038b23892b - sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a - url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c + phone_number: 567a167933138df1080eb0d8ecb0ea44f1dee1ed + PhoneNumberKit: 5b1be7ee4955dfeeb855f51eecdd829ab24b3484 + pointer_interceptor_ios: 9280618c0b2eeb80081a343924aa8ad756c21375 + SDWebImage: dfe95b2466a9823cf9f0c6d01217c06550d7b29a + SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 + sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec + url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe video_player_avfoundation: e9e6f9cae7d7a6d9b43519b0aab382bca60fcfd1 wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 PODFILE CHECKSUM: da491a8b7d2d8eef05b8be02236cf916620dd0f4 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/sample/pubspec.lock b/sample/pubspec.lock index 62412119..a3309f1e 100644 --- a/sample/pubspec.lock +++ b/sample/pubspec.lock @@ -31,7 +31,7 @@ packages: path: ".." relative: true source: path - version: "0.1.1" + version: "0.1.2" boolean_selector: dependency: transitive description: