Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix resize #25

Merged
merged 7 commits into from
Oct 15, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 85 additions & 22 deletions playbook_snapshot/lib/src/snapshot_support.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import 'package:playbook/playbook.dart';
import 'snapshot_device.dart';

class SnapshotSupport {
static const _maxTryResizeCount = 10;
static const _maxSnapshotSize = 50000;

static Future<void> startDevice(
Widget target,
WidgetTester tester,
Expand Down Expand Up @@ -38,25 +41,43 @@ class SnapshotSupport {
// We use scrollController.maxScrollExtent to calculate the snapshot size.
// However, maxScrollExtent may report incorrectly.
// To solve this, we repeatedly calculate size and update size until we can get a stable value.
var lastExtendedSize = device.size;
var lastExtendedSize = Size(
scenario.layout.compressedResizingTarget.needResizingWidth
? device.size.width
: absoluteSize.width,
scenario.layout.compressedResizingTarget.needResizingHeight
? device.size.height
: absoluteSize.height,
);
var resize = 0;
while (true) {
final scrollViews = find
.byWidgetPredicate((widget) => widget is ScrollView)
final scrollables = find
.byWidgetPredicate((widget) => widget is Scrollable)
.evaluate()
.map((e) => e.widget as ScrollView);
if (scrollViews.isEmpty) break;
.map((e) => e.widget as Scrollable);
if (scrollables.isEmpty) break;

var extendedSize = device.size;
for (final scrollView in scrollViews) {
for (final scrollable in scrollables) {
extendedSize = _extendScrollableSnapshotSize(
scrollView: scrollView,
extendedSize: extendedSize,
scrollable: scrollable,
currentExtendedSize: extendedSize,
originSize: lastExtendedSize,
resizingTarget: scenario.layout.compressedResizingTarget,
);
}
if (extendedSize <= lastExtendedSize) break;
lastExtendedSize = extendedSize;
await _setSnapshotSize(tester, lastExtendedSize);
resize++;
if (resize >= _maxTryResizeCount) {
throw StateError(
'Try resizing too many times. Please try to set your scenario to have a fixed size.');
}
if (extendedSize.width >= _maxSnapshotSize || extendedSize.height >= _maxSnapshotSize) {
throw StateError(
'Try resizing too large size ${extendedSize}. Please try to set your scenario to have a fixed size.');
}
}
snapshotSize = lastExtendedSize;
} else {
Expand Down Expand Up @@ -86,31 +107,47 @@ class SnapshotSupport {
}

static Size _extendScrollableSnapshotSize({
required ScrollView scrollView,
required Size extendedSize,
required Scrollable scrollable,
required Size currentExtendedSize,
required Size originSize,
required _CompressedResizingTarget resizingTarget,
}) {
final controller = scrollView.controller;
if (controller == null) {
final controller = scrollable.controller;
ScrollPosition? position;
try {
position = controller?.position;
} catch (_) {}
if (position == null) {
return Size(
max(extendedSize.width, originSize.width),
max(extendedSize.height, originSize.height),
resizingTarget.needResizingWidth
? max(currentExtendedSize.width, originSize.width)
: originSize.width,
resizingTarget.needResizingHeight
? max(currentExtendedSize.height, originSize.height)
: originSize.height,
);
}

final scrollAxis = controller.position.axis;
final maxScrollExtent = controller.position.maxScrollExtent;
final scrollAxis = position.axis;
final maxScrollExtent = position.maxScrollExtent;

final Size newExtendedSize;
switch (scrollAxis) {
case Axis.horizontal:
final height = max(originSize.height, extendedSize.height);
final width = max(maxScrollExtent + originSize.width, extendedSize.width);
return Size(width, height);
final height = max(originSize.height, currentExtendedSize.height);
final width = max(maxScrollExtent + originSize.width, currentExtendedSize.width);
newExtendedSize = Size(width, height);
break;
case Axis.vertical:
final height = max(maxScrollExtent + originSize.height, extendedSize.height);
final width = max(originSize.width, extendedSize.width);
return Size(width, height);
final height = max(maxScrollExtent + originSize.height, currentExtendedSize.height);
final width = max(originSize.width, currentExtendedSize.width);
newExtendedSize = Size(width, height);
break;
}
return Size(
resizingTarget.needResizingWidth ? newExtendedSize.width : originSize.width,
resizingTarget.needResizingHeight ? newExtendedSize.height : originSize.height,
);
}
}

Expand All @@ -123,6 +160,18 @@ extension on ScenarioLayout {
return v is ScenarioLayoutCompressed || h is ScenarioLayoutCompressed;
}

_CompressedResizingTarget get compressedResizingTarget {
if (v is ScenarioLayoutCompressed && h is ScenarioLayoutCompressed) {
return _CompressedResizingTarget.both;
} else if (v is ScenarioLayoutCompressed) {
return _CompressedResizingTarget.vertical;
} else if (h is ScenarioLayoutCompressed) {
return _CompressedResizingTarget.horizontal;
} else {
throw StateError('No need compressed resizing.');
}
}

double absoluteWidth(SnapshotDevice device) {
switch (h.runtimeType) {
case ScenarioLayoutFixed:
Expand All @@ -147,3 +196,17 @@ extension on ScenarioLayout {
return device.size.height;
}
}

enum _CompressedResizingTarget {
horizontal,
vertical,
both,
}

extension on _CompressedResizingTarget {
bool get needResizingWidth =>
this == _CompressedResizingTarget.both || this == _CompressedResizingTarget.horizontal;

bool get needResizingHeight =>
this == _CompressedResizingTarget.both || this == _CompressedResizingTarget.vertical;
}