Hide sensitive content in screenshot
To comply with GDPR it would be helpful to blot out sensitive data.
Proposal
- A
SensitiveFeedbackwidget. Wrapping a widget with it will mean that it will be a back box in the screenshot. - Some sort of
SensitiveFeedbackProvidercontaining aisTakingScreenshotvariable that theSensitiveFeedbackwidget can observe. - Toggle the
isTakingScreenshotvariable inScreenshotController.capture.
I would be happy to implement this myself. But maybe someone has a better proposal before I open a PR.
You could also blot out the content in draw mode, so that the user knows what the screenshot will actually look like.
It would be awesome to make it happen with the SensitiveContent widget from the Flutter framework, instead of building a new widget.
After taking a screenshot, traverse the widget tree, get the positions of it, and do some image manipulation on the screenshot. I guess that would result in a more user friendly API.
I've successfully got all SensitiveContent widgets to be blurred in draw mode and during a screenshot.
The only issue is that we don't know whether a SensitiveContent widget is actually on the page below and therefore not visible. So currently a blurred box is created over widgets that are not even visible.
import 'dart:ui';
import 'package:feedback/src/painter.dart';
import 'package:flutter/material.dart';
class PaintOnChild extends StatelessWidget {
const PaintOnChild({
super.key,
required this.child,
required this.isPaintingActive,
required this.controller,
});
final Widget child;
final bool isPaintingActive;
final PainterController controller;
@override
Widget build(BuildContext context) {
final sensitiveContent = _findSensitiveContent(context);
return Stack(
children: <Widget>[
child,
if (isPaintingActive)
for (final content in sensitiveContent)
Positioned.fromRect(
rect: content,
child: ClipRect(
clipBehavior: Clip.hardEdge,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: SizedBox.expand(),
),
),
),
if (isPaintingActive) Painter(controller),
],
);
}
List<Rect> _findSensitiveContent(BuildContext context) {
final List<Rect> results = [];
// Get the RenderBox of the ancestor to use as the reference frame
final ancestorRenderBox = context.findRenderObject() as RenderBox?;
if (ancestorRenderBox == null || !ancestorRenderBox.hasSize) return results;
void searchElement(Element element) {
if (element.widget is SensitiveContent) {
final targetRenderBox = element.renderObject;
if (targetRenderBox is RenderBox &&
targetRenderBox.hasSize &&
targetRenderBox.attached) {
final size = targetRenderBox.size;
final position = targetRenderBox.localToGlobal(Offset.zero,
ancestor: ancestorRenderBox);
results.add(
Rect.fromLTWH(position.dx, position.dy, size.width, size.height),
);
}
}
element.visitChildren(searchElement);
}
searchElement(context as Element);
return results;
}
}
The other issue of course is that if a SensitiveContent is partially obscured, the widget obscuring it will also be blurred.
I have a successful implementation of the custom widget approach here: https://github.com/JakesMD/feedback/tree/hide-sensitive-content
It's less elegant than directly adding the blurring to PaintOnChild - but it works.