11import 'package:flutter/rendering.dart' ;
2- import 'package:flutter/services.dart' ;
32import 'package:flutter/widgets.dart' ;
43import 'package:meta/meta.dart' ;
54
@@ -10,20 +9,13 @@ import '../sentry_asset_bundle.dart';
109class WidgetFilter {
1110 final items = < WidgetFilterItem > [];
1211 final SentryLogger logger;
13- final bool redactText;
14- final bool redactImages;
12+ final Map <Type , WidgetFilterMaskingConfig > config;
1513 static const _defaultColor = Color .fromARGB (255 , 0 , 0 , 0 );
1614 late double _pixelRatio;
1715 late Rect _bounds;
1816 final _warnedWidgets = < int > {};
19- final AssetBundle _rootAssetBundle;
2017
21- WidgetFilter (
22- {required this .redactText,
23- required this .redactImages,
24- required this .logger,
25- @visibleForTesting AssetBundle ? rootAssetBundle})
26- : _rootAssetBundle = rootAssetBundle ?? rootBundle;
18+ WidgetFilter (this .config, this .logger);
2719
2820 void obscure (BuildContext context, double pixelRatio, Rect bounds) {
2921 _pixelRatio = pixelRatio;
@@ -55,21 +47,20 @@ class WidgetFilter {
5547
5648 @pragma ('vm:prefer-inline' )
5749 bool _obscureIfNeeded (Element element, Widget widget) {
58- Color ? color;
50+ final maskingConfig = config[widget.runtimeType];
51+ if (maskingConfig == null ) {
52+ return false ;
53+ } else if (! maskingConfig.shouldMask (element, widget)) {
54+ logger (SentryLevel .debug, "WidgetFilter skipping: $widget " );
55+ return false ;
56+ }
5957
60- if (redactText && widget is Text ) {
58+ Color ? color;
59+ if (widget is Text ) {
6160 color = widget.style? .color;
62- } else if (redactText && widget is EditableText ) {
61+ } else if (widget is EditableText ) {
6362 color = widget.style.color;
64- } else if (redactImages && widget is Image ) {
65- if (widget.image is AssetBundleImageProvider ) {
66- final image = widget.image as AssetBundleImageProvider ;
67- if (isBuiltInAssetImage (image)) {
68- logger (SentryLevel .debug,
69- "WidgetFilter skipping asset: $widget ($image )." );
70- return false ;
71- }
72- }
63+ } else if (widget is Image ) {
7364 color = widget.color;
7465 } else {
7566 // No other type is currently obscured.
@@ -128,9 +119,10 @@ class WidgetFilter {
128119 return true ;
129120 }
130121
131- @visibleForTesting
122+ @internal
132123 @pragma ('vm:prefer-inline' )
133- bool isBuiltInAssetImage (AssetBundleImageProvider image) {
124+ static bool isBuiltInAssetImage (
125+ AssetBundleImageProvider image, AssetBundle rootAssetBundle) {
134126 late final AssetBundle ? bundle;
135127 if (image is AssetImage ) {
136128 bundle = image.bundle;
@@ -140,8 +132,8 @@ class WidgetFilter {
140132 return false ;
141133 }
142134 return (bundle == null ||
143- bundle == _rootAssetBundle ||
144- (bundle is SentryAssetBundle && bundle.bundle == _rootAssetBundle ));
135+ bundle == rootAssetBundle ||
136+ (bundle is SentryAssetBundle && bundle.bundle == rootAssetBundle ));
145137 }
146138
147139 @pragma ('vm:prefer-inline' )
@@ -165,9 +157,40 @@ class WidgetFilter {
165157 }
166158}
167159
160+ @internal
168161class WidgetFilterItem {
169162 final Color color;
170163 final Rect bounds;
171164
172165 const WidgetFilterItem (this .color, this .bounds);
173166}
167+
168+ @internal
169+ class WidgetFilterMaskingConfig {
170+ static const mask = WidgetFilterMaskingConfig ._(1 , 'mask' );
171+ static const show = WidgetFilterMaskingConfig ._(2 , 'mask' );
172+
173+ final int index;
174+ final String _name;
175+ final bool Function (Element , Widget )? _shouldMask;
176+
177+ const WidgetFilterMaskingConfig ._(this .index, this ._name)
178+ : _shouldMask = null ;
179+ const WidgetFilterMaskingConfig .custom (this ._shouldMask)
180+ : index = 3 ,
181+ _name = 'custom' ;
182+
183+ @override
184+ String toString () => "$WidgetFilterMaskingConfig .$_name " ;
185+
186+ bool shouldMask (Element element, Widget widget) {
187+ switch (this ) {
188+ case mask:
189+ return true ;
190+ case show:
191+ return false ;
192+ default :
193+ return _shouldMask !(element, widget);
194+ }
195+ }
196+ }
0 commit comments