fixed flickering when starting videos
This commit is contained in:
parent
043b2c54aa
commit
72bcf6d4e7
10 changed files with 294 additions and 279 deletions
|
@ -14,6 +14,10 @@ All notable changes to this project will be documented in this file.
|
||||||
- target Android 14 (API 34)
|
- target Android 14 (API 34)
|
||||||
- upgraded Flutter to stable v3.10.6
|
- upgraded Flutter to stable v3.10.6
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- flickering when starting videos
|
||||||
|
|
||||||
## <a id="v1.8.9"></a>[v1.8.9] - 2023-06-04
|
## <a id="v1.8.9"></a>[v1.8.9] - 2023-06-04
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -33,244 +33,250 @@ class VideoSubtitles extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final videoDisplaySize = entry.videoDisplaySize(controller.sarNotifier.value);
|
return ValueListenableBuilder<double?>(
|
||||||
return IgnorePointer(
|
valueListenable: controller.sarNotifier,
|
||||||
child: Consumer<Settings>(
|
builder: (context, sar, child) {
|
||||||
builder: (context, settings, child) {
|
final videoDisplaySize = entry.videoDisplaySize(sar);
|
||||||
final baseTextAlign = settings.subtitleTextAlignment;
|
|
||||||
final baseTextAlignY = settings.subtitleTextPosition.toTextAlignVertical();
|
|
||||||
final baseOutlineWidth = settings.subtitleShowOutline ? 1 : 0;
|
|
||||||
final baseOutlineColor = Colors.black.withOpacity(settings.subtitleTextColor.opacity);
|
|
||||||
final baseShadows = [
|
|
||||||
Shadow(
|
|
||||||
color: baseOutlineColor,
|
|
||||||
offset: baseShadowOffset,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
final baseStyle = TextStyle(
|
|
||||||
color: settings.subtitleTextColor,
|
|
||||||
fontSize: settings.subtitleFontSize,
|
|
||||||
shadows: settings.subtitleShowOutline ? baseShadows : null,
|
|
||||||
);
|
|
||||||
|
|
||||||
final viewportSize = MediaQuery.sizeOf(context);
|
return IgnorePointer(
|
||||||
final isPortrait = MediaQuery.orientationOf(context) == Orientation.portrait;
|
child: Consumer<Settings>(
|
||||||
final bottom = isPortrait ? .5 : .8;
|
builder: (context, settings, child) {
|
||||||
return ValueListenableBuilder<ViewState>(
|
final baseTextAlign = settings.subtitleTextAlignment;
|
||||||
valueListenable: viewStateNotifier,
|
final baseTextAlignY = settings.subtitleTextPosition.toTextAlignVertical();
|
||||||
builder: (context, viewState, child) {
|
final baseOutlineWidth = settings.subtitleShowOutline ? 1 : 0;
|
||||||
final viewPosition = viewState.position;
|
final baseOutlineColor = Colors.black.withOpacity(settings.subtitleTextColor.opacity);
|
||||||
final viewScale = viewState.scale ?? 1;
|
final baseShadows = [
|
||||||
final viewSize = videoDisplaySize * viewScale;
|
Shadow(
|
||||||
final viewOffset = Offset(
|
color: baseOutlineColor,
|
||||||
(viewportSize.width - viewSize.width) / 2,
|
offset: baseShadowOffset,
|
||||||
(viewportSize.height - viewSize.height) / 2,
|
),
|
||||||
|
];
|
||||||
|
final baseStyle = TextStyle(
|
||||||
|
color: settings.subtitleTextColor,
|
||||||
|
fontSize: settings.subtitleFontSize,
|
||||||
|
shadows: settings.subtitleShowOutline ? baseShadows : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
return StreamBuilder<String?>(
|
final viewportSize = MediaQuery.sizeOf(context);
|
||||||
stream: controller.timedTextStream,
|
final isPortrait = MediaQuery.orientationOf(context) == Orientation.portrait;
|
||||||
builder: (context, snapshot) {
|
final bottom = isPortrait ? .5 : .8;
|
||||||
final text = snapshot.data;
|
return ValueListenableBuilder<ViewState>(
|
||||||
if (text == null) return const SizedBox();
|
valueListenable: viewStateNotifier,
|
||||||
|
builder: (context, viewState, child) {
|
||||||
|
final viewPosition = viewState.position;
|
||||||
|
final viewScale = viewState.scale ?? 1;
|
||||||
|
final viewSize = videoDisplaySize * viewScale;
|
||||||
|
final viewOffset = Offset(
|
||||||
|
(viewportSize.width - viewSize.width) / 2,
|
||||||
|
(viewportSize.height - viewSize.height) / 2,
|
||||||
|
);
|
||||||
|
|
||||||
if (debugMode) {
|
return StreamBuilder<String?>(
|
||||||
return Padding(
|
stream: controller.timedTextStream,
|
||||||
padding: const EdgeInsets.only(top: 100.0),
|
builder: (context, snapshot) {
|
||||||
child: Align(
|
final text = snapshot.data;
|
||||||
alignment: Alignment.topLeft,
|
if (text == null) return const SizedBox();
|
||||||
child: OutlinedText(
|
|
||||||
textSpans: [
|
|
||||||
TextSpan(
|
|
||||||
text: text,
|
|
||||||
style: const TextStyle(fontSize: 14),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
outlineWidth: 1,
|
|
||||||
outlineColor: Colors.black,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final styledLine = AssParser.parse(text, baseStyle, viewScale);
|
if (debugMode) {
|
||||||
final position = styledLine.position;
|
return Padding(
|
||||||
final clip = styledLine.clip;
|
padding: const EdgeInsets.only(top: 100.0),
|
||||||
final styledSpans = styledLine.spans;
|
|
||||||
final byExtraStyle = groupBy<StyledSubtitleSpan, SubtitleStyle>(styledSpans, (v) => v.extraStyle);
|
|
||||||
return Stack(
|
|
||||||
children: byExtraStyle.entries.map((kv) {
|
|
||||||
final extraStyle = kv.key;
|
|
||||||
final spans = kv.value.map((v) {
|
|
||||||
final span = v.textSpan;
|
|
||||||
final style = span.style;
|
|
||||||
if (position == null || style == null) return span;
|
|
||||||
|
|
||||||
final letterSpacing = style.letterSpacing;
|
|
||||||
final shadows = style.shadows;
|
|
||||||
return TextSpan(
|
|
||||||
text: span.text,
|
|
||||||
style: style.copyWith(
|
|
||||||
letterSpacing: letterSpacing != null ? letterSpacing * viewScale : null,
|
|
||||||
shadows: shadows
|
|
||||||
?.map((v) => Shadow(
|
|
||||||
color: v.color,
|
|
||||||
offset: v.offset * viewScale,
|
|
||||||
blurRadius: v.blurRadius * viewScale,
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
final drawingPaths = extraStyle.drawingPaths;
|
|
||||||
final textHAlign = extraStyle.hAlign ?? (position != null ? TextAlign.center : baseTextAlign);
|
|
||||||
final textVAlign = extraStyle.vAlign ?? (position != null ? TextAlignVertical.bottom : baseTextAlignY);
|
|
||||||
|
|
||||||
Widget child;
|
|
||||||
if (drawingPaths != null) {
|
|
||||||
child = CustomPaint(
|
|
||||||
painter: SubtitlePathPainter(
|
|
||||||
paths: drawingPaths,
|
|
||||||
scale: viewScale,
|
|
||||||
fillColor: spans.firstOrNull?.style?.color ?? Colors.white,
|
|
||||||
strokeColor: extraStyle.borderColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
final outlineWidth = extraStyle.borderWidth ?? (extraStyle.edgeBlur != null ? 2 : 1);
|
|
||||||
child = OutlinedText(
|
|
||||||
textSpans: spans,
|
|
||||||
outlineWidth: outlineWidth * (position != null ? viewScale : baseOutlineWidth),
|
|
||||||
outlineColor: extraStyle.borderColor ?? baseOutlineColor,
|
|
||||||
outlineBlurSigma: extraStyle.edgeBlur ?? 0,
|
|
||||||
textAlign: textHAlign,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var transform = Matrix4.identity();
|
|
||||||
|
|
||||||
if (position != null) {
|
|
||||||
final para = RenderParagraph(
|
|
||||||
TextSpan(children: spans),
|
|
||||||
textDirection: TextDirection.ltr,
|
|
||||||
textScaleFactor: MediaQuery.textScaleFactorOf(context),
|
|
||||||
)..layout(const BoxConstraints());
|
|
||||||
final textWidth = para.getMaxIntrinsicWidth(double.infinity);
|
|
||||||
final textHeight = para.getMaxIntrinsicHeight(double.infinity);
|
|
||||||
|
|
||||||
late double anchorOffsetX, anchorOffsetY;
|
|
||||||
switch (textHAlign) {
|
|
||||||
case TextAlign.left:
|
|
||||||
anchorOffsetX = 0;
|
|
||||||
case TextAlign.right:
|
|
||||||
anchorOffsetX = -textWidth;
|
|
||||||
case TextAlign.center:
|
|
||||||
default:
|
|
||||||
anchorOffsetX = -textWidth / 2;
|
|
||||||
}
|
|
||||||
switch (textVAlign) {
|
|
||||||
case TextAlignVertical.top:
|
|
||||||
anchorOffsetY = 0;
|
|
||||||
case TextAlignVertical.center:
|
|
||||||
anchorOffsetY = -textHeight / 2;
|
|
||||||
case TextAlignVertical.bottom:
|
|
||||||
anchorOffsetY = -textHeight;
|
|
||||||
}
|
|
||||||
final alignOffset = Offset(anchorOffsetX, anchorOffsetY);
|
|
||||||
final lineOffset = position * viewScale + viewPosition;
|
|
||||||
final translateOffset = viewOffset + lineOffset + alignOffset;
|
|
||||||
transform.translate(translateOffset.dx, translateOffset.dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extraStyle.rotating) {
|
|
||||||
// for perspective
|
|
||||||
transform.setEntry(3, 2, 0.001);
|
|
||||||
final x = -angles.degToRadian(extraStyle.rotationX ?? 0);
|
|
||||||
final y = -angles.degToRadian(extraStyle.rotationY ?? 0);
|
|
||||||
final z = -angles.degToRadian(extraStyle.rotationZ ?? 0);
|
|
||||||
if (x != 0) transform.rotateX(x);
|
|
||||||
if (y != 0) transform.rotateY(y);
|
|
||||||
if (z != 0) transform.rotateZ(z);
|
|
||||||
}
|
|
||||||
if (extraStyle.scaling) {
|
|
||||||
final x = extraStyle.scaleX ?? 1;
|
|
||||||
final y = extraStyle.scaleY ?? 1;
|
|
||||||
transform.scale(x, y);
|
|
||||||
}
|
|
||||||
if (extraStyle.shearing) {
|
|
||||||
final x = extraStyle.shearX ?? 0;
|
|
||||||
final y = extraStyle.shearY ?? 0;
|
|
||||||
transform.multiply(Matrix4(1, y, 0, 0, x, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!transform.isIdentity()) {
|
|
||||||
child = Transform(
|
|
||||||
transform: transform,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position == null) {
|
|
||||||
late double alignX;
|
|
||||||
switch (textHAlign) {
|
|
||||||
case TextAlign.left:
|
|
||||||
alignX = -1;
|
|
||||||
case TextAlign.right:
|
|
||||||
alignX = 1;
|
|
||||||
case TextAlign.center:
|
|
||||||
default:
|
|
||||||
alignX = 0;
|
|
||||||
}
|
|
||||||
late double alignY;
|
|
||||||
switch (textVAlign) {
|
|
||||||
case TextAlignVertical.top:
|
|
||||||
alignY = -bottom;
|
|
||||||
case TextAlignVertical.center:
|
|
||||||
alignY = 0;
|
|
||||||
case TextAlignVertical.bottom:
|
|
||||||
default:
|
|
||||||
alignY = bottom;
|
|
||||||
}
|
|
||||||
child = Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment(alignX, alignY),
|
alignment: Alignment.topLeft,
|
||||||
child: TextBackgroundPainter(
|
child: OutlinedText(
|
||||||
spans: spans,
|
textSpans: [
|
||||||
style: DefaultTextStyle.of(context).style.merge(spans.first.style!.copyWith(
|
TextSpan(
|
||||||
backgroundColor: settings.subtitleBackgroundColor,
|
text: text,
|
||||||
)),
|
style: const TextStyle(fontSize: 14),
|
||||||
textAlign: textHAlign,
|
)
|
||||||
child: child,
|
],
|
||||||
|
outlineWidth: 1,
|
||||||
|
outlineColor: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clip != null) {
|
final styledLine = AssParser.parse(text, baseStyle, viewScale);
|
||||||
final clipOffset = viewOffset + viewPosition;
|
final position = styledLine.position;
|
||||||
final matrix = Matrix4.identity()
|
final clip = styledLine.clip;
|
||||||
..translate(clipOffset.dx, clipOffset.dy)
|
final styledSpans = styledLine.spans;
|
||||||
..scale(viewScale, viewScale);
|
final byExtraStyle = groupBy<StyledSubtitleSpan, SubtitleStyle>(styledSpans, (v) => v.extraStyle);
|
||||||
final transform = matrix.storage;
|
return Stack(
|
||||||
child = ClipPath(
|
children: byExtraStyle.entries.map((kv) {
|
||||||
clipper: SubtitlePathClipper(
|
final extraStyle = kv.key;
|
||||||
paths: clip.map((v) => v.transform(transform)).toList(),
|
final spans = kv.value.map((v) {
|
||||||
scale: viewScale,
|
final span = v.textSpan;
|
||||||
),
|
final style = span.style;
|
||||||
child: child,
|
if (position == null || style == null) return span;
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return child;
|
final letterSpacing = style.letterSpacing;
|
||||||
}).toList(),
|
final shadows = style.shadows;
|
||||||
|
return TextSpan(
|
||||||
|
text: span.text,
|
||||||
|
style: style.copyWith(
|
||||||
|
letterSpacing: letterSpacing != null ? letterSpacing * viewScale : null,
|
||||||
|
shadows: shadows
|
||||||
|
?.map((v) => Shadow(
|
||||||
|
color: v.color,
|
||||||
|
offset: v.offset * viewScale,
|
||||||
|
blurRadius: v.blurRadius * viewScale,
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
final drawingPaths = extraStyle.drawingPaths;
|
||||||
|
final textHAlign = extraStyle.hAlign ?? (position != null ? TextAlign.center : baseTextAlign);
|
||||||
|
final textVAlign = extraStyle.vAlign ?? (position != null ? TextAlignVertical.bottom : baseTextAlignY);
|
||||||
|
|
||||||
|
Widget child;
|
||||||
|
if (drawingPaths != null) {
|
||||||
|
child = CustomPaint(
|
||||||
|
painter: SubtitlePathPainter(
|
||||||
|
paths: drawingPaths,
|
||||||
|
scale: viewScale,
|
||||||
|
fillColor: spans.firstOrNull?.style?.color ?? Colors.white,
|
||||||
|
strokeColor: extraStyle.borderColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final outlineWidth = extraStyle.borderWidth ?? (extraStyle.edgeBlur != null ? 2 : 1);
|
||||||
|
child = OutlinedText(
|
||||||
|
textSpans: spans,
|
||||||
|
outlineWidth: outlineWidth * (position != null ? viewScale : baseOutlineWidth),
|
||||||
|
outlineColor: extraStyle.borderColor ?? baseOutlineColor,
|
||||||
|
outlineBlurSigma: extraStyle.edgeBlur ?? 0,
|
||||||
|
textAlign: textHAlign,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var transform = Matrix4.identity();
|
||||||
|
|
||||||
|
if (position != null) {
|
||||||
|
final para = RenderParagraph(
|
||||||
|
TextSpan(children: spans),
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
textScaleFactor: MediaQuery.textScaleFactorOf(context),
|
||||||
|
)..layout(const BoxConstraints());
|
||||||
|
final textWidth = para.getMaxIntrinsicWidth(double.infinity);
|
||||||
|
final textHeight = para.getMaxIntrinsicHeight(double.infinity);
|
||||||
|
|
||||||
|
late double anchorOffsetX, anchorOffsetY;
|
||||||
|
switch (textHAlign) {
|
||||||
|
case TextAlign.left:
|
||||||
|
anchorOffsetX = 0;
|
||||||
|
case TextAlign.right:
|
||||||
|
anchorOffsetX = -textWidth;
|
||||||
|
case TextAlign.center:
|
||||||
|
default:
|
||||||
|
anchorOffsetX = -textWidth / 2;
|
||||||
|
}
|
||||||
|
switch (textVAlign) {
|
||||||
|
case TextAlignVertical.top:
|
||||||
|
anchorOffsetY = 0;
|
||||||
|
case TextAlignVertical.center:
|
||||||
|
anchorOffsetY = -textHeight / 2;
|
||||||
|
case TextAlignVertical.bottom:
|
||||||
|
anchorOffsetY = -textHeight;
|
||||||
|
}
|
||||||
|
final alignOffset = Offset(anchorOffsetX, anchorOffsetY);
|
||||||
|
final lineOffset = position * viewScale + viewPosition;
|
||||||
|
final translateOffset = viewOffset + lineOffset + alignOffset;
|
||||||
|
transform.translate(translateOffset.dx, translateOffset.dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extraStyle.rotating) {
|
||||||
|
// for perspective
|
||||||
|
transform.setEntry(3, 2, 0.001);
|
||||||
|
final x = -angles.degToRadian(extraStyle.rotationX ?? 0);
|
||||||
|
final y = -angles.degToRadian(extraStyle.rotationY ?? 0);
|
||||||
|
final z = -angles.degToRadian(extraStyle.rotationZ ?? 0);
|
||||||
|
if (x != 0) transform.rotateX(x);
|
||||||
|
if (y != 0) transform.rotateY(y);
|
||||||
|
if (z != 0) transform.rotateZ(z);
|
||||||
|
}
|
||||||
|
if (extraStyle.scaling) {
|
||||||
|
final x = extraStyle.scaleX ?? 1;
|
||||||
|
final y = extraStyle.scaleY ?? 1;
|
||||||
|
transform.scale(x, y);
|
||||||
|
}
|
||||||
|
if (extraStyle.shearing) {
|
||||||
|
final x = extraStyle.shearX ?? 0;
|
||||||
|
final y = extraStyle.shearY ?? 0;
|
||||||
|
transform.multiply(Matrix4(1, y, 0, 0, x, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transform.isIdentity()) {
|
||||||
|
child = Transform(
|
||||||
|
transform: transform,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position == null) {
|
||||||
|
late double alignX;
|
||||||
|
switch (textHAlign) {
|
||||||
|
case TextAlign.left:
|
||||||
|
alignX = -1;
|
||||||
|
case TextAlign.right:
|
||||||
|
alignX = 1;
|
||||||
|
case TextAlign.center:
|
||||||
|
default:
|
||||||
|
alignX = 0;
|
||||||
|
}
|
||||||
|
late double alignY;
|
||||||
|
switch (textVAlign) {
|
||||||
|
case TextAlignVertical.top:
|
||||||
|
alignY = -bottom;
|
||||||
|
case TextAlignVertical.center:
|
||||||
|
alignY = 0;
|
||||||
|
case TextAlignVertical.bottom:
|
||||||
|
default:
|
||||||
|
alignY = bottom;
|
||||||
|
}
|
||||||
|
child = Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment(alignX, alignY),
|
||||||
|
child: TextBackgroundPainter(
|
||||||
|
spans: spans,
|
||||||
|
style: DefaultTextStyle.of(context).style.merge(spans.first.style!.copyWith(
|
||||||
|
backgroundColor: settings.subtitleBackgroundColor,
|
||||||
|
)),
|
||||||
|
textAlign: textHAlign,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clip != null) {
|
||||||
|
final clipOffset = viewOffset + viewPosition;
|
||||||
|
final matrix = Matrix4.identity()
|
||||||
|
..translate(clipOffset.dx, clipOffset.dy)
|
||||||
|
..scale(viewScale, viewScale);
|
||||||
|
final transform = matrix.storage;
|
||||||
|
child = ClipPath(
|
||||||
|
clipper: SubtitlePathClipper(
|
||||||
|
paths: clip.map((v) => v.transform(transform)).toList(),
|
||||||
|
scale: viewScale,
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,10 +51,9 @@ class _VideoViewState extends State<VideoView> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StreamBuilder<VideoStatus>(
|
return StreamBuilder<VideoStatus>(
|
||||||
stream: controller.statusStream,
|
stream: controller.statusStream,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) => controller.isReady ? controller.buildPlayerWidget(context) : const SizedBox(),
|
||||||
return controller.isReady ? controller.buildPlayerWidget(context) : const SizedBox();
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// not called when looping
|
// not called when looping
|
||||||
|
|
|
@ -445,16 +445,6 @@ class _AvesMagnifierState extends State<AvesMagnifier> with TickerProviderStateM
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
);
|
);
|
||||||
|
|
||||||
// `Matrix4.scale` uses dynamic typing and can throw `UnimplementedError` on wrong types
|
|
||||||
final double effectiveScale = (applyScale ? scale : null) ?? 1.0;
|
|
||||||
child = Transform(
|
|
||||||
transform: Matrix4.identity()
|
|
||||||
..translate(position.dx, position.dy)
|
|
||||||
..scale(effectiveScale),
|
|
||||||
alignment: basePosition,
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
|
|
||||||
return MagnifierGestureDetector(
|
return MagnifierGestureDetector(
|
||||||
hitDetector: this,
|
hitDetector: this,
|
||||||
onScaleStart: onScaleStart,
|
onScaleStart: onScaleStart,
|
||||||
|
@ -464,17 +454,29 @@ class _AvesMagnifierState extends State<AvesMagnifier> with TickerProviderStateM
|
||||||
onDoubleTap: onDoubleTap,
|
onDoubleTap: onDoubleTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: widget.viewportPadding,
|
padding: widget.viewportPadding,
|
||||||
child: LayoutBuilder(builder: (context, constraints) {
|
child: LayoutBuilder(
|
||||||
controller.setScaleBoundaries((controller.scaleBoundaries ?? ScaleBoundaries.zero).copyWith(
|
builder: (context, constraints) {
|
||||||
allowOriginalScaleBeyondRange: widget.allowOriginalScaleBeyondRange,
|
final boundaries = (controller.scaleBoundaries ?? ScaleBoundaries.zero).copyWith(
|
||||||
minScale: widget.minScale,
|
allowOriginalScaleBeyondRange: widget.allowOriginalScaleBeyondRange,
|
||||||
maxScale: widget.maxScale,
|
minScale: widget.minScale,
|
||||||
initialScale: widget.initialScale,
|
maxScale: widget.maxScale,
|
||||||
viewportSize: constraints.biggest,
|
initialScale: widget.initialScale,
|
||||||
contentSize: widget.contentSize.isEmpty == false ? widget.contentSize : constraints.biggest,
|
viewportSize: constraints.biggest,
|
||||||
));
|
contentSize: widget.contentSize.isEmpty == false ? widget.contentSize : constraints.biggest,
|
||||||
return child;
|
);
|
||||||
}),
|
controller.setScaleBoundaries(boundaries);
|
||||||
|
|
||||||
|
// `Matrix4.scale` uses dynamic typing and can throw `UnimplementedError` on wrong types
|
||||||
|
final double effectiveScale = (applyScale ? scale : null) ?? 1.0;
|
||||||
|
return Transform(
|
||||||
|
transform: Matrix4.identity()
|
||||||
|
..translate(position.dx, position.dy)
|
||||||
|
..scale(effectiveScale),
|
||||||
|
alignment: basePosition,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,10 +5,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _flutterfire_internals
|
name: _flutterfire_internals
|
||||||
sha256: a742f71d7f3484253a623b30e19256aa4668ecbb3de6ad1beb0bcf8d4777ecd8
|
sha256: "5dce45a06d386358334eb1689108db6455d90ceb0d75848d5f4819283d4ee2b8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.3"
|
version: "1.3.4"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -68,10 +68,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_core
|
name: firebase_core
|
||||||
sha256: a4a99204da264a0aa9d54a332ea0315ce7b0768075139c77abefe98093dd98be
|
sha256: "2e9324f719e90200dc7d3c4f5d2abc26052f9f2b995d3b6626c47a0dfe1c8192"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.14.0"
|
version: "2.15.0"
|
||||||
firebase_core_platform_interface:
|
firebase_core_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -92,18 +92,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics
|
name: firebase_crashlytics
|
||||||
sha256: "398012cf7838f8a373a25da65dd62fc3a3f4abe4b5f886caa634952c3387dce3"
|
sha256: "3607b46342537f98df18b130b6f5ab25cee6981a3a782e1a7b121d04dfea3caa"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.3"
|
version: "3.3.4"
|
||||||
firebase_crashlytics_platform_interface:
|
firebase_crashlytics_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics_platform_interface
|
name: firebase_crashlytics_platform_interface
|
||||||
sha256: "39dfcc9a5ddfaa0588ad67f1016174dd9e19f6b31f592b8641bd559399567592"
|
sha256: c63abeb87b18f6e6d4bf6bb3977f15d2d9281a049d93fe098e83e56dcbf7da06
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.6.3"
|
version: "3.6.4"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
@ -212,10 +212,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_platform_interface
|
name: google_maps_flutter_platform_interface
|
||||||
sha256: "308f0af138fa78e8224d598d46ca182673874d0ef4d754b7157c073b5b4b8e0d"
|
sha256: cd310faa7fba3df10ab3f852719f832eaa223e4b315ac46af986572d1cec222f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.7"
|
version: "2.3.0"
|
||||||
google_maps_flutter_web:
|
google_maps_flutter_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -383,9 +383,11 @@ class IjkVideoController extends AvesVideoController {
|
||||||
return ValueListenableBuilder<double?>(
|
return ValueListenableBuilder<double?>(
|
||||||
valueListenable: sarNotifier,
|
valueListenable: sarNotifier,
|
||||||
builder: (context, sar, child) {
|
builder: (context, sar, child) {
|
||||||
|
if (sar == null) return const SizedBox();
|
||||||
|
|
||||||
// derive DAR (Display Aspect Ratio) from SAR (Storage Aspect Ratio), if any
|
// derive DAR (Display Aspect Ratio) from SAR (Storage Aspect Ratio), if any
|
||||||
// e.g. 960x536 (~16:9) with SAR 4:3 should be displayed as ~2.39:1
|
// e.g. 960x536 (~16:9) with SAR 4:3 should be displayed as ~2.39:1
|
||||||
final dar = entry.displayAspectRatio * (sar ?? 1);
|
final dar = entry.displayAspectRatio * sar;
|
||||||
return FijkView(
|
return FijkView(
|
||||||
player: _instance,
|
player: _instance,
|
||||||
fit: FijkFit(
|
fit: FijkFit(
|
||||||
|
|
|
@ -207,9 +207,11 @@ class MpvVideoController extends AvesVideoController {
|
||||||
return ValueListenableBuilder<double?>(
|
return ValueListenableBuilder<double?>(
|
||||||
valueListenable: sarNotifier,
|
valueListenable: sarNotifier,
|
||||||
builder: (context, sar, child) {
|
builder: (context, sar, child) {
|
||||||
|
if (sar == null) return const SizedBox();
|
||||||
|
|
||||||
// derive DAR (Display Aspect Ratio) from SAR (Storage Aspect Ratio), if any
|
// derive DAR (Display Aspect Ratio) from SAR (Storage Aspect Ratio), if any
|
||||||
// e.g. 960x536 (~16:9) with SAR 4:3 should be displayed as ~2.39:1
|
// e.g. 960x536 (~16:9) with SAR 4:3 should be displayed as ~2.39:1
|
||||||
final dar = entry.displayAspectRatio * (sar ?? 1);
|
final dar = entry.displayAspectRatio * sar;
|
||||||
return Video(
|
return Video(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
fill: Colors.transparent,
|
fill: Colors.transparent,
|
||||||
|
|
|
@ -173,7 +173,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: media_kit
|
path: media_kit
|
||||||
ref: main
|
ref: main
|
||||||
resolved-ref: "6d0f0401b8d87596a6167fd629912cff92003edc"
|
resolved-ref: a1a1d14c5f920442898f22ea61dc9e357a671112
|
||||||
url: "https://github.com/alexmercerind/media_kit"
|
url: "https://github.com/alexmercerind/media_kit"
|
||||||
source: git
|
source: git
|
||||||
version: "1.0.2"
|
version: "1.0.2"
|
||||||
|
@ -182,7 +182,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: media_kit_libs_android_video
|
path: media_kit_libs_android_video
|
||||||
ref: main
|
ref: main
|
||||||
resolved-ref: "6d0f0401b8d87596a6167fd629912cff92003edc"
|
resolved-ref: a1a1d14c5f920442898f22ea61dc9e357a671112
|
||||||
url: "https://github.com/alexmercerind/media_kit"
|
url: "https://github.com/alexmercerind/media_kit"
|
||||||
source: git
|
source: git
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
@ -191,7 +191,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: media_kit_native_event_loop
|
path: media_kit_native_event_loop
|
||||||
ref: main
|
ref: main
|
||||||
resolved-ref: "6d0f0401b8d87596a6167fd629912cff92003edc"
|
resolved-ref: a1a1d14c5f920442898f22ea61dc9e357a671112
|
||||||
url: "https://github.com/alexmercerind/media_kit"
|
url: "https://github.com/alexmercerind/media_kit"
|
||||||
source: git
|
source: git
|
||||||
version: "1.0.6"
|
version: "1.0.6"
|
||||||
|
@ -200,7 +200,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: media_kit_video
|
path: media_kit_video
|
||||||
ref: main
|
ref: main
|
||||||
resolved-ref: "6d0f0401b8d87596a6167fd629912cff92003edc"
|
resolved-ref: a1a1d14c5f920442898f22ea61dc9e357a671112
|
||||||
url: "https://github.com/alexmercerind/media_kit"
|
url: "https://github.com/alexmercerind/media_kit"
|
||||||
source: git
|
source: git
|
||||||
version: "1.0.2"
|
version: "1.0.2"
|
||||||
|
|
32
pubspec.lock
32
pubspec.lock
|
@ -13,10 +13,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _flutterfire_internals
|
name: _flutterfire_internals
|
||||||
sha256: a742f71d7f3484253a623b30e19256aa4668ecbb3de6ad1beb0bcf8d4777ecd8
|
sha256: "5dce45a06d386358334eb1689108db6455d90ceb0d75848d5f4819283d4ee2b8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.3"
|
version: "1.3.4"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -365,10 +365,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core
|
name: firebase_core
|
||||||
sha256: a4a99204da264a0aa9d54a332ea0315ce7b0768075139c77abefe98093dd98be
|
sha256: "2e9324f719e90200dc7d3c4f5d2abc26052f9f2b995d3b6626c47a0dfe1c8192"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.14.0"
|
version: "2.15.0"
|
||||||
firebase_core_platform_interface:
|
firebase_core_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -389,18 +389,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics
|
name: firebase_crashlytics
|
||||||
sha256: "398012cf7838f8a373a25da65dd62fc3a3f4abe4b5f886caa634952c3387dce3"
|
sha256: "3607b46342537f98df18b130b6f5ab25cee6981a3a782e1a7b121d04dfea3caa"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.3"
|
version: "3.3.4"
|
||||||
firebase_crashlytics_platform_interface:
|
firebase_crashlytics_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_crashlytics_platform_interface
|
name: firebase_crashlytics_platform_interface
|
||||||
sha256: "39dfcc9a5ddfaa0588ad67f1016174dd9e19f6b31f592b8641bd559399567592"
|
sha256: c63abeb87b18f6e6d4bf6bb3977f15d2d9281a049d93fe098e83e56dcbf7da06
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.6.3"
|
version: "3.6.4"
|
||||||
flex_color_picker:
|
flex_color_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -620,10 +620,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_platform_interface
|
name: google_maps_flutter_platform_interface
|
||||||
sha256: "308f0af138fa78e8224d598d46ca182673874d0ef4d754b7157c073b5b4b8e0d"
|
sha256: cd310faa7fba3df10ab3f852719f832eaa223e4b315ac46af986572d1cec222f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.7"
|
version: "2.3.0"
|
||||||
google_maps_flutter_web:
|
google_maps_flutter_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1206,10 +1206,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_foundation
|
name: shared_preferences_foundation
|
||||||
sha256: b046999bf0ff58f04c364491bb803dcfa8f42e47b19c75478f53d323684a8cc1
|
sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.2"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1484,10 +1484,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_macos
|
name: url_launcher_macos
|
||||||
sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e"
|
sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.5"
|
version: "3.0.6"
|
||||||
url_launcher_platform_interface:
|
url_launcher_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1596,10 +1596,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
|
sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
xml:
|
xml:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
Loading…
Reference in a new issue