From bceb8562fe1b05c5df7a9eeab85177b07874e4b1 Mon Sep 17 00:00:00 2001 From: Luke Walton Date: Thu, 23 May 2024 16:51:41 +0100 Subject: [PATCH] chore: update to match internal repo (#24) fix: [TM-42170] Support links in table fix:[TM-42460] Reset resetPreferredOrientations after camera dispose fix: [TM-43252] taking time to capture an image --- example/lib/pages/components/html_view.dart | 3 ++ .../organisms/camera/camera_page.dart | 25 +++++++-- .../html_preview/table_html_extension.dart | 51 +++++++++++++++++++ lib/src/utils/tools.dart | 1 + lib/src/utils/tools/system_chrome.dart | 48 +++++++++++++++++ 5 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 lib/src/utils/tools/system_chrome.dart diff --git a/example/lib/pages/components/html_view.dart b/example/lib/pages/components/html_view.dart index 292be2d..6ffc12d 100644 --- a/example/lib/pages/components/html_view.dart +++ b/example/lib/pages/components/html_view.dart @@ -725,6 +725,9 @@ class HtmlPreview extends StatelessWidget { return ZdsHtmlContainer( data, showReadMore: false, + onLinkTap: (_, __, ___) { + print('Link tapped'); + }, ); }, itemCount: htmlList.length, diff --git a/lib/src/components/organisms/camera/camera_page.dart b/lib/src/components/organisms/camera/camera_page.dart index 4521593..d748a25 100644 --- a/lib/src/components/organisms/camera/camera_page.dart +++ b/lib/src/components/organisms/camera/camera_page.dart @@ -46,6 +46,7 @@ class ZdsCamera extends StatelessWidget { this.cameraMode = ZdsCameraMode.photo, this.maxVideoDuration, this.showPreview = true, + this.saveGPSLocation = false, this.photoPathBuilder, this.videoPathBuilder, this.filters, @@ -60,6 +61,9 @@ class ZdsCamera extends StatelessWidget { /// - [showPreview] determines whether the camera preview is shown before selecting a file, enabled by default. final bool showPreview; + /// - [saveGPSLocation] determines whether the camera output be tagged with GPS location, disabled by default. + final bool saveGPSLocation; + /// A builder for the path to save the photo or video file. /// /// This builder is used to specify the path to save the photo or video file. @@ -87,6 +91,7 @@ class ZdsCamera extends StatelessWidget { BuildContext context, { bool showPreview = true, bool rootNavigator = true, + bool saveGPSLocation = false, CaptureRequestBuilder? photoPathBuilder, CaptureRequestBuilder? videoPathBuilder, List? filters, @@ -98,6 +103,7 @@ class ZdsCamera extends StatelessWidget { ZdsFadePageRouteBuilder( builder: (context) => ZdsCamera( showPreview: showPreview, + saveGPSLocation: saveGPSLocation, photoPathBuilder: photoPathBuilder, videoPathBuilder: videoPathBuilder, filters: filters, @@ -242,7 +248,7 @@ class ZdsCamera extends StatelessWidget { ), ) : SaveConfig.photo( - exifPreferences: ExifPreferences(saveGPSLocation: true), + exifPreferences: ExifPreferences(saveGPSLocation: saveGPSLocation), pathBuilder: videoPathBuilder ?? (sensors) async { final Directory extDir = await getTemporaryDirectory(); @@ -270,7 +276,8 @@ class ZdsCamera extends StatelessWidget { ..add(DiagnosticsProperty('showPreview', showPreview)) ..add(ObjectFlagProperty.has('photoPathBuilder', photoPathBuilder)) ..add(ObjectFlagProperty.has('videoPathBuilder', videoPathBuilder)) - ..add(IterableProperty('filters', filters)); + ..add(IterableProperty('filters', filters)) + ..add(DiagnosticsProperty('saveGPSLocation', saveGPSLocation)); } } @@ -357,7 +364,10 @@ class _CameraWrapperState extends State<_CameraWrapper> { children: [ if (widget.state is! VideoRecordingCameraState) GestureDetector( - onTap: () => Navigator.of(context).pop(), + onTap: () async { + await ZdsSystemChrome.resetAppOrientations(); + if (context.mounted) Navigator.of(context).pop(); + }, child: AwesomeCircleWidget( theme: theme, size: 45, @@ -782,18 +792,23 @@ class _PreviewActions extends StatelessWidget { elevation: 0, shape: const CircleBorder(), backgroundColor: Colors.black38, - onPressed: () => Navigator.of(context).pop(false), + onPressed: () async => _onPop(context, false), child: const Icon(Icons.close, color: ZetaColorBase.white), ), FloatingActionButton( elevation: 0, shape: const CircleBorder(), backgroundColor: Colors.black38, - onPressed: () => Navigator.of(context).pop(true), + onPressed: () async => _onPop(context, true), child: const Icon(Icons.done, color: ZetaColorBase.white), ), ], ), ); } + + Future _onPop(BuildContext context, bool result) async { + await ZdsSystemChrome.resetAppOrientations(); + if (context.mounted) Navigator.of(context).pop(result); + } } diff --git a/lib/src/components/organisms/html_preview/table_html_extension.dart b/lib/src/components/organisms/html_preview/table_html_extension.dart index 94977c8..4ec36dc 100644 --- a/lib/src/components/organisms/html_preview/table_html_extension.dart +++ b/lib/src/components/organisms/html_preview/table_html_extension.dart @@ -1,10 +1,12 @@ import 'dart:math'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html_table/flutter_html_table.dart'; import 'package:flutter_layout_grid/flutter_layout_grid.dart'; import 'package:html/dom.dart' as html; +import 'package:zeta_flutter/zeta_flutter.dart'; /// Supported tags for [TableHtmlExtension] to use with flutter_html library. const zdsTableTags = { @@ -261,6 +263,18 @@ class ZdsTableHtmlExtension extends HtmlExtension { ), node: context.node, ); + } else if (context.elementName == 'a') { + return InteractiveElement( + name: context.elementName, + children: children, + href: context.attributes['href'], + style: Style( + color: ZetaColorBase.blue.shade50, + textDecoration: TextDecoration.underline, + ), + node: context.node, + elementId: context.id, + ); } return StyledElement( @@ -295,6 +309,14 @@ class ZdsTableHtmlExtension extends HtmlExtension { ), ), ); + } else if (context.elementName == 'a' && + context.inlineSpanChildren != null && + context.inlineSpanChildren!.isNotEmpty) { + return TextSpan( + children: context.inlineSpanChildren!.map((childSpan) { + return _processInteractableChild(context, childSpan); + }).toList(), + ); } return WidgetSpan( @@ -306,6 +328,35 @@ class ZdsTableHtmlExtension extends HtmlExtension { } } +InlineSpan _processInteractableChild( + ExtensionContext context, + InlineSpan childSpan, +) { + void onTap() => context.parser.internalOnAnchorTap?.call( + (context.styledElement! as InteractiveElement).href, + context.attributes, + context.node as html.Element, + ); + + if (childSpan is TextSpan) { + return TextSpan( + text: childSpan.text, + children: childSpan.children?.map((e) => _processInteractableChild(context, e)).toList(), + style: childSpan.style, + semanticsLabel: childSpan.semanticsLabel, + recognizer: TapGestureRecognizer()..onTap = onTap, + ); + } else { + return WidgetSpan( + child: GestureDetector( + key: AnchorKey.of(context.parser.key, context.styledElement), + onTap: onTap, + child: (childSpan as WidgetSpan).child, + ), + ); + } +} + /// Recursively gets a flattened list of the table's /// cell descendants List _getCellDescendants(List children) { diff --git a/lib/src/utils/tools.dart b/lib/src/utils/tools.dart index 12c0ec0..8bbfafb 100644 --- a/lib/src/utils/tools.dart +++ b/lib/src/utils/tools.dart @@ -4,5 +4,6 @@ export 'tools/frame_mixin.dart'; export 'tools/keyboard_dismiss.dart'; export 'tools/modifiers.dart'; export 'tools/nested_flow.dart'; +export 'tools/system_chrome.dart'; export 'tools/tab_navigator.dart'; export 'tools/utils.dart'; diff --git a/lib/src/utils/tools/system_chrome.dart b/lib/src/utils/tools/system_chrome.dart new file mode 100644 index 0000000..25c26c0 --- /dev/null +++ b/lib/src/utils/tools/system_chrome.dart @@ -0,0 +1,48 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +/// Controls orientations of the application interface +class ZdsSystemChrome { + static List _orientations = [ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]; + + /// Get the set of orientations the application interface can + /// be displayed in. + static List get appOrientations => _orientations; + + /// Specifies the set of orientations the application interface can + /// be displayed in. + /// + /// The `orientation` argument is a list of [DeviceOrientation] enum values. + static Future setPreferredOrientations(List? orientations) async { + final platformMediaQuery = MediaQueryData.fromView(PlatformDispatcher.instance.views.first); + if (orientations == null || orientations.isEmpty) { + if (platformMediaQuery.size.shortestSide < 600) { + _orientations = [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]; + } else { + _orientations = [ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]; + } + } else { + _orientations = orientations; + } + + await resetAppOrientations(); + } + + /// Set the set of orientations the application interface can + /// be displayed in. + static Future resetAppOrientations() async { + await SystemChrome.setPreferredOrientations(appOrientations); + } +}