diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..094b2f0 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +staged_files=() +while IFS= read -r -d '' file; do + staged_files+=("$file") +done < <(git diff --cached --name-only -z --diff-filter=ACMR) + +if command -v fvm >/dev/null 2>&1; then + DART_DISABLE_TELEMETRY=1 fvm dart format . +else + DART_DISABLE_TELEMETRY=1 dart format . +fi + +if ((${#staged_files[@]})); then + git add -- "${staged_files[@]}" +fi diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..530eae0 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @zhukeev diff --git a/.github/ISSUE_TEMPLATE/issue_report.yml b/.github/ISSUE_TEMPLATE/issue_report.yml new file mode 100644 index 0000000..bf715ed --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue_report.yml @@ -0,0 +1,56 @@ +name: Issue +description: Report a bug or request a feature +title: "[Issue]: " +labels: + - triage +body: + - type: dropdown + id: type + attributes: + label: Type + options: + - Bug + - "Feature request" + - Question + validations: + required: true + - type: textarea + id: summary + attributes: + label: Summary + description: What happened or what you want to add. + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: For bugs, include minimal steps. + placeholder: "1. ...\n2. ...\n3. ..." + - type: textarea + id: expected + attributes: + label: Expected behavior + - type: textarea + id: actual + attributes: + label: Actual behavior + - type: input + id: package_version + attributes: + label: Package version + placeholder: "1.0.23" + - type: input + id: flutter_version + attributes: + label: Flutter version + placeholder: "3.27.0" + - type: input + id: platform + attributes: + label: Platform + placeholder: "iOS / Android / Web / macOS / Windows / Linux" + - type: textarea + id: additional + attributes: + label: Additional context diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml new file mode 100644 index 0000000..f2d4cda --- /dev/null +++ b/.github/workflows/auto-assign.yml @@ -0,0 +1,32 @@ +name: Auto assign + +on: + issues: + types: [opened, reopened] + pull_request_target: + types: [opened, reopened, ready_for_review] + +permissions: + issues: write + pull-requests: write + +jobs: + assign: + runs-on: ubuntu-latest + steps: + - name: Add assignee + uses: actions/github-script@v7 + with: + script: | + const assignees = ['zhukeev']; + const issue_number = context.payload.pull_request + ? context.payload.pull_request.number + : context.issue.number; + const { owner, repo } = context.repo; + + await github.rest.issues.addAssignees({ + owner, + repo, + issue_number, + assignees, + }); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe26e49..5eeb337 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,21 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Detect code changes + id: changes + uses: dorny/paths-filter@v3 + with: + filters: | + code: + - "lib/**" + - "test/**" + - "example/**" + - "shaders/**" + - "assets/**" + - "pubspec.yaml" + - "analysis_options.yaml" + - "analysis_options.yml" + - name: Setup Flutter uses: subosito/flutter-action@v2 with: @@ -23,7 +38,7 @@ jobs: run: flutter pub get - name: Check formatting - run: dart format --line-length=120 --output=none --set-exit-if-changed lib test example + run: dart format --output=none --set-exit-if-changed . - name: Run analysis run: flutter analyze @@ -33,9 +48,11 @@ jobs: working-directory: example - name: Run tests + if: steps.changes.outputs.code == 'true' run: flutter test - name: Run golden tests + if: steps.changes.outputs.code == 'true' run: flutter test test/golden_test.dart - name: Install pana diff --git a/example/lib/main.dart b/example/lib/main.dart index 1f8bd6c..61ccb6e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -35,7 +35,8 @@ class _DemoListPage extends StatelessWidget { _DemoEntry('SpoilerTextField', () => const SpoilerTextFieldPage()), _DemoEntry('SpoilerTextWrapper', () => const SpoilerTextWrapperPage()), _DemoEntry('SpoilerOverlay', () => const SpoilerOverlayPage()), - _DemoEntry('SpoilerOverlay Full', () => const SpoilerOverlayPage(fullPage: true)), + _DemoEntry('SpoilerOverlay Full', + () => const SpoilerOverlayPage(fullPage: true)), ]; return Scaffold( diff --git a/example/lib/pages/spoiler_overlay_page.dart b/example/lib/pages/spoiler_overlay_page.dart index 784f97d..0b11a6c 100644 --- a/example/lib/pages/spoiler_overlay_page.dart +++ b/example/lib/pages/spoiler_overlay_page.dart @@ -18,7 +18,8 @@ class _SpoilerOverlayPageState extends State { 'https://img.freepik.com/premium-photo/drawing-female-superhero-female-character_1308175-151081.jpg?w=1800'; bool divided = false; - WidgetSpoilerConfig config(bool shaders) => WidgetSpoilerConfig.defaultConfig().copyWith( + WidgetSpoilerConfig config(bool shaders) => + WidgetSpoilerConfig.defaultConfig().copyWith( enableGestureReveal: true, particleConfig: const ParticleConfig( density: .1, diff --git a/example/lib/pages/spoiler_text_field_page.dart b/example/lib/pages/spoiler_text_field_page.dart index 13ee1b3..1c94d51 100644 --- a/example/lib/pages/spoiler_text_field_page.dart +++ b/example/lib/pages/spoiler_text_field_page.dart @@ -9,7 +9,8 @@ class SpoilerTextFieldPage extends StatefulWidget { } class _SpoilerTextFieldPageState extends State { - final _controller = TextEditingController(text: 'This is a spoiler! Tap to reveal'); + final _controller = + TextEditingController(text: 'This is a spoiler! Tap to reveal'); @override void dispose() { diff --git a/lib/extension/rect_x.dart b/lib/extension/rect_x.dart index 43a818a..7dc68e1 100644 --- a/lib/extension/rect_x.dart +++ b/lib/extension/rect_x.dart @@ -14,17 +14,24 @@ extension RectX on Rect { /// ``` /// bool containsOffset(Offset offset) { - return bottom >= offset.dy && top <= offset.dy && left <= offset.dx && right >= offset.dx; + return bottom >= offset.dy && + top <= offset.dy && + left <= offset.dx && + right >= offset.dx; } (Rect, Rect, Rect, Rect) divideRect() { final halfWidth = width / 2; final halfHeight = height / 2; - final topLeft = Rect.fromLTRB(left, top, left + halfWidth, top + halfHeight); - final topRight = Rect.fromLTRB(left + halfWidth, top, right, top + halfHeight); - final bottomLeft = Rect.fromLTRB(left, top + halfHeight, left + halfWidth, bottom); - final bottomRight = Rect.fromLTRB(left + halfWidth, top + halfHeight, right, bottom); + final topLeft = + Rect.fromLTRB(left, top, left + halfWidth, top + halfHeight); + final topRight = + Rect.fromLTRB(left + halfWidth, top, right, top + halfHeight); + final bottomLeft = + Rect.fromLTRB(left, top + halfHeight, left + halfWidth, bottom); + final bottomRight = + Rect.fromLTRB(left + halfWidth, top + halfHeight, right, bottom); return (topLeft, topRight, bottomLeft, bottomRight); } diff --git a/lib/models/fade_config.dart b/lib/models/fade_config.dart index b4d4d6c..54b92f3 100644 --- a/lib/models/fade_config.dart +++ b/lib/models/fade_config.dart @@ -15,5 +15,8 @@ class FadeConfig { @override bool operator ==(Object other) => - identical(this, other) || other is FadeConfig && padding == other.padding && edgeThickness == other.edgeThickness; + identical(this, other) || + other is FadeConfig && + padding == other.padding && + edgeThickness == other.edgeThickness; } diff --git a/lib/models/shader_config.dart b/lib/models/shader_config.dart index b043d91..dd2e4bd 100644 --- a/lib/models/shader_config.dart +++ b/lib/models/shader_config.dart @@ -144,7 +144,8 @@ class ShaderConfig { /// Glitch stripes with RGB splits. factory ShaderConfig.glitchStripes() => ShaderConfig( customShaderPath: 'packages/spoiler_widget/shaders/glitch_stripes.frag', - onGetShaderUniforms: (rect, time, seed, fadeOffset, isFading, fadeRadius, config) { + onGetShaderUniforms: + (rect, time, seed, fadeOffset, isFading, fadeRadius, config) { return [ rect.width, rect.height, @@ -177,7 +178,8 @@ class ShaderConfig { /// Liquid Spectrum (HSV FBM) shader. factory ShaderConfig.liquidSpectrum() => const ShaderConfig( - customShaderPath: 'packages/spoiler_widget/shaders/liquid_spectrum.frag', + customShaderPath: + 'packages/spoiler_widget/shaders/liquid_spectrum.frag', onGetShaderUniforms: _baseUniforms, ); } diff --git a/lib/models/spoiler_config.dart b/lib/models/spoiler_config.dart index 67b1d14..f0ec55a 100644 --- a/lib/models/spoiler_config.dart +++ b/lib/models/spoiler_config.dart @@ -116,10 +116,12 @@ class SpoilerConfig { this.shaderConfig, }) : particleConfig = particleConfig ?? ParticleConfig( - density: particleDensity ?? ParticleConfig.defaultConfig().density, + density: + particleDensity ?? ParticleConfig.defaultConfig().density, speed: particleSpeed ?? ParticleConfig.defaultConfig().speed, color: particleColor ?? ParticleConfig.defaultConfig().color, - maxParticleSize: maxParticleSize ?? ParticleConfig.defaultConfig().maxParticleSize, + maxParticleSize: maxParticleSize ?? + ParticleConfig.defaultConfig().maxParticleSize, ), fadeConfig = _resolveFadeConfig( fadeConfig: fadeConfig, @@ -129,10 +131,16 @@ class SpoilerConfig { ) { assert( particleConfig == null || - (particleDensity == null && particleSpeed == null && particleColor == null && maxParticleSize == null), + (particleDensity == null && + particleSpeed == null && + particleColor == null && + maxParticleSize == null), ); assert( - fadeConfig == null || (enableFadeAnimation == null && fadeRadius == null && fadeEdgeThickness == null), + fadeConfig == null || + (enableFadeAnimation == null && + fadeRadius == null && + fadeEdgeThickness == null), ); } @@ -179,31 +187,50 @@ class SpoilerConfig { ValueChanged? onSpoilerVisibilityChanged, ShaderConfig? shaderConfig, }) { - final bool legacyParticleOverridesProvided = - particleDensity != null || particleSpeed != null || particleColor != null || maxParticleSize != null; + final bool legacyParticleOverridesProvided = particleDensity != null || + particleSpeed != null || + particleColor != null || + maxParticleSize != null; - final bool legacyFadeOverridesProvided = - enableFadeAnimation != null || fadeRadius != null || fadeEdgeThickness != null; + final bool legacyFadeOverridesProvided = enableFadeAnimation != null || + fadeRadius != null || + fadeEdgeThickness != null; - final ParticleConfig? nextParticleConfig = - legacyParticleOverridesProvided ? null : (particleConfig ?? this.particleConfig); + final ParticleConfig? nextParticleConfig = legacyParticleOverridesProvided + ? null + : (particleConfig ?? this.particleConfig); - final FadeConfig? nextFadeConfig = legacyFadeOverridesProvided ? null : (fadeConfig ?? this.fadeConfig); + final FadeConfig? nextFadeConfig = + legacyFadeOverridesProvided ? null : (fadeConfig ?? this.fadeConfig); return SpoilerConfig( - particleDensity: legacyParticleOverridesProvided ? (particleDensity ?? this.particleDensity) : null, - particleSpeed: legacyParticleOverridesProvided ? (particleSpeed ?? this.particleSpeed) : null, - particleColor: legacyParticleOverridesProvided ? (particleColor ?? this.particleColor) : null, - maxParticleSize: legacyParticleOverridesProvided ? (maxParticleSize ?? this.maxParticleSize) : null, - enableFadeAnimation: legacyFadeOverridesProvided ? (enableFadeAnimation ?? this.enableFadeAnimation) : null, - fadeRadius: legacyFadeOverridesProvided ? (fadeRadius ?? this.fadeRadius) : null, - fadeEdgeThickness: legacyFadeOverridesProvided ? (fadeEdgeThickness ?? this.fadeEdgeThickness) : null, + particleDensity: legacyParticleOverridesProvided + ? (particleDensity ?? this.particleDensity) + : null, + particleSpeed: legacyParticleOverridesProvided + ? (particleSpeed ?? this.particleSpeed) + : null, + particleColor: legacyParticleOverridesProvided + ? (particleColor ?? this.particleColor) + : null, + maxParticleSize: legacyParticleOverridesProvided + ? (maxParticleSize ?? this.maxParticleSize) + : null, + enableFadeAnimation: legacyFadeOverridesProvided + ? (enableFadeAnimation ?? this.enableFadeAnimation) + : null, + fadeRadius: + legacyFadeOverridesProvided ? (fadeRadius ?? this.fadeRadius) : null, + fadeEdgeThickness: legacyFadeOverridesProvided + ? (fadeEdgeThickness ?? this.fadeEdgeThickness) + : null, particleConfig: nextParticleConfig, fadeConfig: nextFadeConfig, isEnabled: isEnabled ?? this.isEnabled, enableGestureReveal: enableGestureReveal ?? this.enableGestureReveal, maskConfig: maskConfig ?? this.maskConfig, - onSpoilerVisibilityChanged: onSpoilerVisibilityChanged ?? this.onSpoilerVisibilityChanged, + onSpoilerVisibilityChanged: + onSpoilerVisibilityChanged ?? this.onSpoilerVisibilityChanged, shaderConfig: shaderConfig ?? this.shaderConfig, ); } diff --git a/lib/models/spoiler_controller.dart b/lib/models/spoiler_controller.dart index 11a11e0..36eb5a3 100644 --- a/lib/models/spoiler_controller.dart +++ b/lib/models/spoiler_controller.dart @@ -110,12 +110,14 @@ class SpoilerController extends ChangeNotifier { bool get isEnabled => _isEnabled; /// True if the fade animation is active. - bool get isFading => _config.fadeConfig != null && _fadeCtrl != null && _fadeCtrl!.isAnimating; + bool get isFading => + _config.fadeConfig != null && _fadeCtrl != null && _fadeCtrl!.isAnimating; /// The bounding rectangle for the spoiler region. Rect get spoilerBounds => _spoilerBounds; - Rect get _splashRect => Rect.fromCircle(center: _fadeCenter, radius: _fadeRadius); + Rect get _splashRect => + Rect.fromCircle(center: _fadeCenter, radius: _fadeRadius); /// A path function that clips only the circular fade area if there’s a non-zero fade radius. Path createClipPath(Size size) { @@ -179,12 +181,14 @@ class SpoilerController extends ChangeNotifier { /// [config]: Configuration for speed, density, color, etc. /// [rects]: Optional explicit list of rectangles (e.g. for individual words). /// If provided, this is preferred for shader rendering to ensure precise per-rect shapes. - void initializeParticles(Path path, SpoilerConfig config, {List? rects}) { + void initializeParticles(Path path, SpoilerConfig config, + {List? rects}) { final previousShaderPath = _config.shaderConfig?.customShaderPath; final nextShaderPath = config.shaderConfig?.customShaderPath; // Ensure maxParticleSize is valid - assert(config.particleConfig.maxParticleSize >= 1, 'maxParticleSize must be >= 1'); + assert(config.particleConfig.maxParticleSize >= 1, + 'maxParticleSize must be >= 1'); _config = config; _spoilerRects = rects ?? []; _cachedClipPath = null; // Invalidate cache @@ -259,7 +263,8 @@ class SpoilerController extends ChangeNotifier { duration: const Duration(milliseconds: 300), vsync: _tickerProvider, ); - _fadeAnim = Tween(begin: 0, end: 1).animate(_fadeCtrl!)..addListener(_updateFadeRadius); + _fadeAnim = Tween(begin: 0, end: 1).animate(_fadeCtrl!) + ..addListener(_updateFadeRadius); } } @@ -297,7 +302,8 @@ class SpoilerController extends ChangeNotifier { /// Toggle the spoiler effect on/off. Optional [fadeOffset] for the radial center. bool toggle(Offset fadeOffset) { // If we’re mid-fade, skip to avoid partial toggles. - if ((_config.fadeConfig != null && isFading) || !_spoilerPath.contains(fadeOffset)) { + if ((_config.fadeConfig != null && isFading) || + !_spoilerPath.contains(fadeOffset)) { return false; } @@ -310,7 +316,9 @@ class SpoilerController extends ChangeNotifier { } void setFadeCenter(Offset fadeCenter) { - _fadeCenter = _spoilerBounds == Rect.zero ? fadeCenter : _spoilerBounds.getNearestPoint(fadeCenter); + _fadeCenter = _spoilerBounds == Rect.zero + ? fadeCenter + : _spoilerBounds.getNearestPoint(fadeCenter); _cachedClipPath = null; if (_fadeAnim != null) { _updateFadeRadius(); diff --git a/lib/models/spoiler_drawing_strategy.dart b/lib/models/spoiler_drawing_strategy.dart index cb7c50c..a28f1c9 100644 --- a/lib/models/spoiler_drawing_strategy.dart +++ b/lib/models/spoiler_drawing_strategy.dart @@ -54,7 +54,8 @@ class ShaderSpoilerDrawer implements SpoilerDrawer { CircleImage? _sprite; ParticleConfig? _spriteConfig; - static const String _particlesShaderPath = 'packages/spoiler_widget/shaders/particles.frag'; + static const String _particlesShaderPath = + 'packages/spoiler_widget/shaders/particles.frag'; static bool _isParticleShaderPath(String? path) { if (path == null) return false; @@ -104,8 +105,10 @@ class ShaderSpoilerDrawer implements SpoilerDrawer { final spoilerBounds = context.spoilerBounds; final spoilerRects = context.spoilerRects; final config = context.config; - final bool isParticleShader = _isParticleShaderPath(config.shaderConfig?.customShaderPath); - final CircleImage? sprite = isParticleShader ? _ensureSprite(config.particleConfig) : null; + final bool isParticleShader = + _isParticleShaderPath(config.shaderConfig?.customShaderPath); + final CircleImage? sprite = + isParticleShader ? _ensureSprite(config.particleConfig) : null; final Rect logicalBounds = spoilerBounds; @@ -186,7 +189,8 @@ class ShaderSpoilerDrawer implements SpoilerDrawer { } } -int _channelToInt8(double value) => (value * 255.0).round().clamp(0, 255).toInt(); +int _channelToInt8(double value) => + (value * 255.0).round().clamp(0, 255).toInt(); int _colorToArgb(Color color) { return (_channelToInt8(color.a) << 24) | @@ -205,7 +209,8 @@ class AtlasSpoilerDrawer implements SpoilerDrawer { final List _particles = []; // Visual assets & config - CircleImage _circleImage = CircleImageFactory.create(diameter: 1, color: Colors.white); + CircleImage _circleImage = + CircleImageFactory.create(diameter: 1, color: Colors.white); double _maxParticleSize = 1; Color _particleColor = Colors.white; double _particleSpeed = 1; @@ -257,7 +262,9 @@ class AtlasSpoilerDrawer implements SpoilerDrawer { final rect = path.getBounds(); final screenArea = rect.width * rect.height; - final particleArea = pi * pow(config.particleConfig.maxParticleSize * 0.5, 2) * config.particleConfig.areaFactor; + final particleArea = pi * + pow(config.particleConfig.maxParticleSize * 0.5, 2) * + config.particleConfig.areaFactor; final rawCount = (screenArea * coverage) / particleArea; final particleCount = rawCount.round(); @@ -278,7 +285,9 @@ class AtlasSpoilerDrawer implements SpoilerDrawer { for (int i = 0; i < _particles.length; i++) { final p = _particles[i]; - _particles[i] = (p.life <= 0.1) ? _createRandomParticlePath(p.path) : p.moveToRandomAngle(); + _particles[i] = (p.life <= 0.1) + ? _createRandomParticlePath(p.path) + : p.moveToRandomAngle(); } } @@ -334,7 +343,8 @@ class AtlasSpoilerDrawer implements SpoilerDrawer { min(p.dx - bounds.left, bounds.right - p.dx), min(p.dy - bounds.top, bounds.bottom - p.dy), ); - final edgeFade = edgeDist <= 0.0 ? 0.0 : smoothstep(0.0, boundaryFadePx, edgeDist); + final edgeFade = + edgeDist <= 0.0 ? 0.0 : smoothstep(0.0, boundaryFadePx, edgeDist); final particleRadius = max(spriteRadius * lifeScale, 0.0001); final edgeClamp = (edgeDist / particleRadius).clamp(0.0, 1.0); final edgeScale = edgeFade * edgeClamp; @@ -346,7 +356,8 @@ class AtlasSpoilerDrawer implements SpoilerDrawer { if (distSq < radiusSq) { final dist = sqrt(distSq); final scale = (dist > fadeRadius - fadeEdgeThickness) ? 1.5 : 1.0; - final color = (dist > fadeRadius - fadeEdgeThickness) ? Colors.white : p.color; + final color = + (dist > fadeRadius - fadeEdgeThickness) ? Colors.white : p.color; final scaled = scale * lifeScale * edgeScale; final edgeColor = color.withValues(alpha: color.a * edgeScale); @@ -360,7 +371,9 @@ class AtlasSpoilerDrawer implements SpoilerDrawer { rects[transformIndex + 2] = _circleImage.dimension.toDouble(); rects[transformIndex + 3] = _circleImage.dimension.toDouble(); - colors[index] = edgeScale > 0.0 ? _colorToArgb(edgeColor) : _colorToArgb(Colors.transparent); + colors[index] = edgeScale > 0.0 + ? _colorToArgb(edgeColor) + : _colorToArgb(Colors.transparent); if (edgeScale <= 0.0) { transforms[transformIndex + 0] = 0.0; } @@ -385,7 +398,9 @@ class AtlasSpoilerDrawer implements SpoilerDrawer { rects[transformIndex + 3] = _circleImage.dimension.toDouble(); final edgeColor = p.color.withValues(alpha: p.color.a * edgeScale); - colors[index] = edgeScale > 0.0 ? _colorToArgb(edgeColor) : _colorToArgb(Colors.transparent); + colors[index] = edgeScale > 0.0 + ? _colorToArgb(edgeColor) + : _colorToArgb(Colors.transparent); if (edgeScale <= 0.0) { transforms[transformIndex + 0] = 0.0; } diff --git a/lib/models/spoiler_mask.dart b/lib/models/spoiler_mask.dart index 1f5f905..8812824 100644 --- a/lib/models/spoiler_mask.dart +++ b/lib/models/spoiler_mask.dart @@ -32,6 +32,7 @@ class SpoilerMask { int points, double innerRatio, ) { - return ParticlePathPreset.buildStarPath(center, outerRadius, points, innerRatio); + return ParticlePathPreset.buildStarPath( + center, outerRadius, points, innerRatio); } } diff --git a/lib/models/spoiler_spots_controller.dart b/lib/models/spoiler_spots_controller.dart index f6bc5ad..123c608 100644 --- a/lib/models/spoiler_spots_controller.dart +++ b/lib/models/spoiler_spots_controller.dart @@ -69,7 +69,8 @@ class SpoilerSpotsController extends SpoilerController { /// [configuration] includes fields like [WidgetSpoilerConfig.maxActiveWaves], which limit concurrency. /// [rects] optionally provide per-line bounds. @override - void initializeParticles(Path path, SpoilerConfig configuration, {List? rects}) { + void initializeParticles(Path path, SpoilerConfig configuration, + {List? rects}) { if (configuration is WidgetSpoilerConfig) { _config = configuration; } @@ -166,8 +167,12 @@ class SpoilerSpotsController extends SpoilerController { var waveEndpoint = adjustedEnd; if (!spoilerBounds.containsOffset(waveEndpoint)) { waveEndpoint = Offset( - spoilerBounds.left + margin + _random.nextDouble() * (spoilerBounds.width - 2 * margin), - spoilerBounds.top + margin + _random.nextDouble() * (spoilerBounds.height - 2 * margin), + spoilerBounds.left + + margin + + _random.nextDouble() * (spoilerBounds.width - 2 * margin), + spoilerBounds.top + + margin + + _random.nextDouble() * (spoilerBounds.height - 2 * margin), ); } @@ -180,7 +185,8 @@ class SpoilerSpotsController extends SpoilerController { ); // If that offset is inside, use it; otherwise revert to waveEndpoint. - final finalOffset = current.path.contains(randomOffset) ? randomOffset : waveEndpoint; + final finalOffset = + current.path.contains(randomOffset) ? randomOffset : waveEndpoint; // Build a two-phase tween: (current -> waveEndpoint -> finalOffset) final offsetTween = TweenSequence([ diff --git a/lib/models/text_spoiler_configs.dart b/lib/models/text_spoiler_configs.dart index aa3c928..aa5cdf8 100644 --- a/lib/models/text_spoiler_configs.dart +++ b/lib/models/text_spoiler_configs.dart @@ -116,8 +116,10 @@ class TextSpoilerConfig extends SpoilerConfig { int? maxLines, bool? isEllipsis, }) { - final bool legacyParticleOverrides = - particleDensity != null || particleSpeed != null || particleColor != null || maxParticleSize != null; + final bool legacyParticleOverrides = particleDensity != null || + particleSpeed != null || + particleColor != null || + maxParticleSize != null; final ParticleConfig nextParticleConfig = particleConfig ?? (legacyParticleOverrides @@ -125,19 +127,23 @@ class TextSpoilerConfig extends SpoilerConfig { density: particleDensity ?? this.particleConfig.density, speed: particleSpeed ?? this.particleConfig.speed, color: particleColor ?? this.particleConfig.color, - maxParticleSize: maxParticleSize ?? this.particleConfig.maxParticleSize, + maxParticleSize: + maxParticleSize ?? this.particleConfig.maxParticleSize, shapePreset: this.particleConfig.shapePreset, ) : this.particleConfig); - final bool legacyFadeOverrides = enableFadeAnimation != null || fadeRadius != null || fadeEdgeThickness != null; + final bool legacyFadeOverrides = enableFadeAnimation != null || + fadeRadius != null || + fadeEdgeThickness != null; final FadeConfig? nextFadeConfig = fadeConfig ?? (legacyFadeOverrides ? ((enableFadeAnimation ?? (this.fadeConfig != null)) ? FadeConfig( padding: fadeRadius ?? (this.fadeConfig?.padding ?? 10.0), - edgeThickness: fadeEdgeThickness ?? (this.fadeConfig?.edgeThickness ?? 20.0), + edgeThickness: fadeEdgeThickness ?? + (this.fadeConfig?.edgeThickness ?? 20.0), ) : null) : this.fadeConfig); @@ -148,7 +154,8 @@ class TextSpoilerConfig extends SpoilerConfig { isEnabled: isEnabled ?? this.isEnabled, enableGestureReveal: enableGestureReveal ?? this.enableGestureReveal, maskConfig: maskConfig ?? this.maskConfig, - onSpoilerVisibilityChanged: onSpoilerVisibilityChanged ?? this.onSpoilerVisibilityChanged, + onSpoilerVisibilityChanged: + onSpoilerVisibilityChanged ?? this.onSpoilerVisibilityChanged, textStyle: textStyle ?? this.textStyle, textSelection: textSelection ?? this.textSelection, textAlign: textAlign ?? this.textAlign, diff --git a/lib/models/widget_spoiler_config.dart b/lib/models/widget_spoiler_config.dart index 6db4623..11cbfd4 100644 --- a/lib/models/widget_spoiler_config.dart +++ b/lib/models/widget_spoiler_config.dart @@ -89,8 +89,10 @@ class WidgetSpoilerConfig extends SpoilerConfig { ImageFilter? imageFilter, int? maxActiveWaves, }) { - final bool legacyParticleOverridesProvided = - particleDensity != null || particleSpeed != null || particleColor != null || maxParticleSize != null; + final bool legacyParticleOverridesProvided = particleDensity != null || + particleSpeed != null || + particleColor != null || + maxParticleSize != null; final ParticleConfig nextParticleConfig = particleConfig ?? (legacyParticleOverridesProvided @@ -98,20 +100,23 @@ class WidgetSpoilerConfig extends SpoilerConfig { density: particleDensity ?? this.particleConfig.density, speed: particleSpeed ?? this.particleConfig.speed, color: particleColor ?? this.particleConfig.color, - maxParticleSize: maxParticleSize ?? this.particleConfig.maxParticleSize, + maxParticleSize: + maxParticleSize ?? this.particleConfig.maxParticleSize, shapePreset: this.particleConfig.shapePreset, ) : this.particleConfig); - final bool legacyFadeOverridesProvided = - enableFadeAnimation != null || fadeRadius != null || fadeEdgeThickness != null; + final bool legacyFadeOverridesProvided = enableFadeAnimation != null || + fadeRadius != null || + fadeEdgeThickness != null; final FadeConfig? nextFadeConfig = fadeConfig ?? (legacyFadeOverridesProvided ? ((enableFadeAnimation ?? (this.fadeConfig != null)) ? FadeConfig( padding: fadeRadius ?? (this.fadeConfig?.padding ?? 10.0), - edgeThickness: fadeEdgeThickness ?? (this.fadeConfig?.edgeThickness ?? 20.0), + edgeThickness: fadeEdgeThickness ?? + (this.fadeConfig?.edgeThickness ?? 20.0), ) : null) : this.fadeConfig); @@ -125,7 +130,8 @@ class WidgetSpoilerConfig extends SpoilerConfig { isEnabled: isEnabled ?? this.isEnabled, enableGestureReveal: enableGestureReveal ?? this.enableGestureReveal, maskConfig: maskConfig ?? this.maskConfig, - onSpoilerVisibilityChanged: onSpoilerVisibilityChanged ?? this.onSpoilerVisibilityChanged, + onSpoilerVisibilityChanged: + onSpoilerVisibilityChanged ?? this.onSpoilerVisibilityChanged, ); } diff --git a/lib/spoiler_overlay_widget.dart b/lib/spoiler_overlay_widget.dart index 6da57ff..2a2f7b5 100644 --- a/lib/spoiler_overlay_widget.dart +++ b/lib/spoiler_overlay_widget.dart @@ -17,7 +17,8 @@ class SpoilerOverlay extends StatefulWidget { State createState() => _SpoilerOverlayState(); } -class _SpoilerOverlayState extends State with TickerProviderStateMixin { +class _SpoilerOverlayState extends State + with TickerProviderStateMixin { late SpoilerController _spoilerController; Rect _spoilerBounds = Rect.zero; @@ -33,7 +34,8 @@ class _SpoilerOverlayState extends State with TickerProviderStat void _initializeSpoilerBounds(Size size) { _spoilerBounds = Rect.fromLTWH(0, 0, size.width, size.height); - _spoilerController.initializeParticles(Path()..addRect(_spoilerBounds), widget.config); + _spoilerController.initializeParticles( + Path()..addRect(_spoilerBounds), widget.config); } @override @@ -75,14 +77,16 @@ class _SpoilerOverlayState extends State with TickerProviderStat return SpoilerRenderObjectWidget( onAfterPaint: (canvas, size) => _onPaint(canvas, size), onClipPath: (size) { - if (_spoilerController.isEnabled && !_spoilerController.isFading) { + if (_spoilerController.isEnabled && + !_spoilerController.isFading) { return Path()..addRect(Offset.zero & size); } return _spoilerController.createClipPath(size); }, enableOverlay: true, - imageFilter: _spoilerController.isEnabled ? widget.config.imageFilter : null, + imageFilter: + _spoilerController.isEnabled ? widget.config.imageFilter : null, child: child!, ); }, diff --git a/lib/spoiler_text_form_field.dart b/lib/spoiler_text_form_field.dart index 57326f4..9502874 100644 --- a/lib/spoiler_text_form_field.dart +++ b/lib/spoiler_text_form_field.dart @@ -22,11 +22,14 @@ class SpoilerTextFieldWrapper extends StatefulWidget { final ValueChanged? onSelectionChanged; @override - State createState() => _SpoilerTextFieldWrapperState(); + State createState() => + _SpoilerTextFieldWrapperState(); } -class _SpoilerTextFieldWrapperState extends State with TickerProviderStateMixin { - late final SpoilerController _spoilerController = SpoilerController(vsync: this); +class _SpoilerTextFieldWrapperState extends State + with TickerProviderStateMixin { + late final SpoilerController _spoilerController = + SpoilerController(vsync: this); TextSelection _spoilerSelection = const TextSelection.collapsed(offset: 0); @@ -46,7 +49,7 @@ class _SpoilerTextFieldWrapperState extends State with return (context, editableTextState) { final selection = editableTextState.textEditingValue.selection; - final items = editableTextState.contextMenuButtonItems.map((e) => e).toList(); + final items = editableTextState.contextMenuButtonItems.toList(); if (selection.isValid && !selection.isCollapsed) { items.add( @@ -107,7 +110,8 @@ class _SpoilerTextFieldWrapperState extends State with } }, textSelection: _spoilerSelection, - onClipPath: (size) => _spoilerController.createSplashPathMaskClipper(size), + onClipPath: (size) => + _spoilerController.createSplashPathMaskClipper(size), onInit: (rects) { final path = Path(); for (final rect in rects) { diff --git a/lib/spoiler_text_widget.dart b/lib/spoiler_text_widget.dart index 8726dd9..cd7cff6 100644 --- a/lib/spoiler_text_widget.dart +++ b/lib/spoiler_text_widget.dart @@ -20,8 +20,10 @@ class SpoilerText extends StatefulWidget { State createState() => _SpoilerTextState(); } -class _SpoilerTextState extends State with TickerProviderStateMixin { - late final SpoilerController _spoilerController = SpoilerController(vsync: this); +class _SpoilerTextState extends State + with TickerProviderStateMixin { + late final SpoilerController _spoilerController = + SpoilerController(vsync: this); void _setSpoilerRegions(List regions) { final Path spoilerMaskPath = Path(); diff --git a/lib/spoiler_text_wrapper.dart b/lib/spoiler_text_wrapper.dart index 9a0e1da..632ded0 100644 --- a/lib/spoiler_text_wrapper.dart +++ b/lib/spoiler_text_wrapper.dart @@ -25,8 +25,10 @@ class SpoilerTextWrapper extends StatefulWidget { State createState() => _SpoilerTextWrapperState(); } -class _SpoilerTextWrapperState extends State with TickerProviderStateMixin { - late final SpoilerController _spoilerController = SpoilerController(vsync: this); +class _SpoilerTextWrapperState extends State + with TickerProviderStateMixin { + late final SpoilerController _spoilerController = + SpoilerController(vsync: this); @override void didUpdateWidget(covariant SpoilerTextWrapper oldWidget) { @@ -65,13 +67,15 @@ class _SpoilerTextWrapperState extends State with TickerProv _spoilerController.drawParticles(canvas); } }, - onClipPath: (size) => _spoilerController.createSplashPathMaskClipper(size), + onClipPath: (size) => + _spoilerController.createSplashPathMaskClipper(size), onInit: (rects) { final path = Path(); for (final rect in rects) { path.addRect(rect); } - _spoilerController.initializeParticles(path, widget.config, rects: rects); + _spoilerController.initializeParticles(path, widget.config, + rects: rects); }, child: child, ), diff --git a/lib/utils/spoiler_shader_renderer.dart b/lib/utils/spoiler_shader_renderer.dart index 751a5d1..7fa8cb0 100644 --- a/lib/utils/spoiler_shader_renderer.dart +++ b/lib/utils/spoiler_shader_renderer.dart @@ -26,7 +26,8 @@ class SpoilerShaderRenderer { final shader = program.fragmentShader(); return SpoilerShaderRenderer._(shader: shader); } catch (e) { - debugPrint('SpoilerShaderRenderer: Failed to load shader "$assetPath". Error: $e'); + debugPrint( + 'SpoilerShaderRenderer: Failed to load shader "$assetPath". Error: $e'); return null; } } diff --git a/lib/utils/text_layout_client.dart b/lib/utils/text_layout_client.dart index a9670a0..c5f8c2f 100644 --- a/lib/utils/text_layout_client.dart +++ b/lib/utils/text_layout_client.dart @@ -19,7 +19,8 @@ class RenderEditableLayoutClient implements TextLayoutClient { double get preferredLineHeight => render.preferredLineHeight; @override - List getBoxesForSelection(TextSelection selection) => render.getBoxesForSelection(selection); + List getBoxesForSelection(TextSelection selection) => + render.getBoxesForSelection(selection); } class RenderParagraphLayoutClient implements TextLayoutClient { @@ -44,7 +45,8 @@ class RenderParagraphLayoutClient implements TextLayoutClient { } @override - List getBoxesForSelection(TextSelection selection) => render.getBoxesForSelection(selection); + List getBoxesForSelection(TextSelection selection) => + render.getBoxesForSelection(selection); } class TextPainterLayoutClient implements TextLayoutClient { @@ -53,7 +55,8 @@ class TextPainterLayoutClient implements TextLayoutClient { final TextPainter painter; @override - List getBoxesForSelection(TextSelection selection) => painter.getBoxesForSelection(selection); + List getBoxesForSelection(TextSelection selection) => + painter.getBoxesForSelection(selection); @override double get preferredLineHeight => painter.preferredLineHeight; @@ -69,8 +72,10 @@ class TextPainterLayoutClient implements TextLayoutClient { required TextSelection selection, bool skipWhitespace = true, }) { - final int rawStart = selection.start < selection.end ? selection.start : selection.end; - final int rawEnd = selection.start > selection.end ? selection.start : selection.end; + final int rawStart = + selection.start < selection.end ? selection.start : selection.end; + final int rawEnd = + selection.start > selection.end ? selection.start : selection.end; final int start = rawStart.clamp(0, text.length); final int end = rawEnd.clamp(0, text.length); if (start >= end) return (null, []); diff --git a/lib/widgets/canvas_callback_painter.dart b/lib/widgets/canvas_callback_painter.dart index 0bb7481..c985d52 100644 --- a/lib/widgets/canvas_callback_painter.dart +++ b/lib/widgets/canvas_callback_painter.dart @@ -14,5 +14,6 @@ class CustomPainterCanvasCallback extends CustomPainter { void paint(Canvas canvas, Size size) => onPaint.call(canvas, size); @override - bool shouldRepaint(covariant CustomPainter oldDelegate) => oldDelegate != this; + bool shouldRepaint(covariant CustomPainter oldDelegate) => + oldDelegate != this; } diff --git a/lib/widgets/spoiler_render_object.dart b/lib/widgets/spoiler_render_object.dart index 7495d4a..0046c27 100644 --- a/lib/widgets/spoiler_render_object.dart +++ b/lib/widgets/spoiler_render_object.dart @@ -47,7 +47,8 @@ class SpoilerRenderObjectWidget extends SingleChildRenderObjectWidget { } @override - void updateRenderObject(BuildContext context, covariant RenderSpoiler renderObject) { + void updateRenderObject( + BuildContext context, covariant RenderSpoiler renderObject) { renderObject ..onPaint = onPaint ..onAfterPaint = onAfterPaint @@ -87,7 +88,8 @@ class RenderSpoiler extends RenderProxyBox { final Set _listenedOffsets = {}; - List _findRenderEditables(RenderObject root, {Set? offsets}) { + List _findRenderEditables(RenderObject root, + {Set? offsets}) { final out = []; void visit(RenderObject node) { @@ -188,12 +190,17 @@ class RenderSpoiler extends RenderProxyBox { void paint(PaintingContext context, Offset offset) { final visitedOffsets = {}; final childRo = child; - final editables = - childRo != null ? _findRenderEditables(childRo, offsets: visitedOffsets) : const []; - final paragraphs = childRo != null ? _findRenderParagraphs(childRo) : const []; + final editables = childRo != null + ? _findRenderEditables(childRo, offsets: visitedOffsets) + : const []; + final paragraphs = childRo != null + ? _findRenderParagraphs(childRo) + : const []; final selection = _textSelection; - final shouldRecalculate = _rectsDirty || _lastSelection != selection || _cachedSelectionRects.isEmpty; + final shouldRecalculate = _rectsDirty || + _lastSelection != selection || + _cachedSelectionRects.isEmpty; if (shouldRecalculate) { final collected = _collectSpoilerRects( editables: editables, @@ -210,13 +217,18 @@ class RenderSpoiler extends RenderProxyBox { if (_enableOverlay) { super.paint(context, offset); - if (clipPath == null && _onPaint == null && _onAfterPaint == null && _imageFilter == null) { + if (clipPath == null && + _onPaint == null && + _onAfterPaint == null && + _imageFilter == null) { _syncEditableOffsets(visitedOffsets); return; } if (clipPath != null) { - context.pushClipPath(needsCompositing, offset, paintBounds.shift(offset), clipPath, (c, o) { + context.pushClipPath( + needsCompositing, offset, paintBounds.shift(offset), clipPath, + (c, o) { _paintOverlayContent(c, o); }); } else { @@ -246,8 +258,8 @@ class RenderSpoiler extends RenderProxyBox { if (_onPaint != null) { if (particleClipPath != null) { - spoilerContext.pushClipPath(needsCompositing, layerOffset, paintBounds.shift(layerOffset), particleClipPath, - (c, o) { + spoilerContext.pushClipPath(needsCompositing, layerOffset, + paintBounds.shift(layerOffset), particleClipPath, (c, o) { _drawParticles(c, o, _onPaint); }); } else { @@ -256,7 +268,8 @@ class RenderSpoiler extends RenderProxyBox { } if (clipPath != null) { - spoilerContext.pushClipPath(needsCompositing, layerOffset, paintBounds.shift(layerOffset), clipPath, (c, o) { + spoilerContext.pushClipPath(needsCompositing, layerOffset, + paintBounds.shift(layerOffset), clipPath, (c, o) { _paintChildWithFilter(c, o); }); } else { @@ -265,8 +278,8 @@ class RenderSpoiler extends RenderProxyBox { if (_onAfterPaint != null) { if (particleClipPath != null) { - spoilerContext.pushClipPath(needsCompositing, layerOffset, paintBounds.shift(layerOffset), particleClipPath, - (c, o) { + spoilerContext.pushClipPath(needsCompositing, layerOffset, + paintBounds.shift(layerOffset), particleClipPath, (c, o) { _drawParticles(c, o, _onAfterPaint); }); } else { @@ -293,7 +306,8 @@ class RenderSpoiler extends RenderProxyBox { _drawParticles(context, offset, _onPaint); if (_imageFilter != null) { - context.pushLayer(BackdropFilterLayer(filter: _imageFilter!), (childContext, childOffset) { + context.pushLayer(BackdropFilterLayer(filter: _imageFilter!), + (childContext, childOffset) { _drawParticles(childContext, childOffset, _onAfterPaint); }, offset); } else { @@ -301,7 +315,8 @@ class RenderSpoiler extends RenderProxyBox { } } - void _drawParticles(PaintingContext currentContext, Offset currentOffset, PaintCallback? callback) { + void _drawParticles(PaintingContext currentContext, Offset currentOffset, + PaintCallback? callback) { if (callback != null) { final canvas = currentContext.canvas; canvas.save(); @@ -363,7 +378,8 @@ class RenderSpoiler extends RenderProxyBox { super.detach(); } - SpoilerGeometry? _buildEditableGeometry(RenderEditable editable, TextSelection selection) { + SpoilerGeometry? _buildEditableGeometry( + RenderEditable editable, TextSelection selection) { final text = editable.plainText; if (text.isEmpty) return null; return buildSpoilerGeometry( @@ -374,7 +390,8 @@ class RenderSpoiler extends RenderProxyBox { ); } - List _buildParagraphSelectionRects(RenderParagraph paragraph, int start, int end) { + List _buildParagraphSelectionRects( + RenderParagraph paragraph, int start, int end) { final text = paragraph.text.toPlainText(); if (text.isEmpty) return const []; @@ -385,7 +402,8 @@ class RenderSpoiler extends RenderProxyBox { final geom = buildSpoilerGeometry( layout: RenderParagraphLayoutClient(paragraph), text: text, - selection: TextSelection(baseOffset: clampedStart, extentOffset: clampedEnd), + selection: + TextSelection(baseOffset: clampedStart, extentOffset: clampedEnd), skipWhitespace: true, ); return geom?.rects ?? const []; @@ -424,8 +442,10 @@ class RenderSpoiler extends RenderProxyBox { appendEditable(editable, selection); } - final int rawStart = selection.start < selection.end ? selection.start : selection.end; - final int rawEnd = selection.start > selection.end ? selection.start : selection.end; + final int rawStart = + selection.start < selection.end ? selection.start : selection.end; + final int rawEnd = + selection.start > selection.end ? selection.start : selection.end; int paragraphOffset = 0; for (final paragraph in paragraphs) { @@ -508,7 +528,8 @@ class SpoilerPaintingContext extends PaintingContext { ); final paintOffset = _editablePaintOffset(child); for (final b in boxes) { - spoilerRects.add(_normalizeEditableRect(b.toRect().shift(offset + paintOffset), child)); + spoilerRects.add(_normalizeEditableRect( + b.toRect().shift(offset + paintOffset), child)); } } } @@ -518,7 +539,8 @@ class SpoilerPaintingContext extends PaintingContext { } @override - PaintingContext createChildContext(ContainerLayer childLayer, ui.Rect bounds) { + PaintingContext createChildContext( + ContainerLayer childLayer, ui.Rect bounds) { return _ChildSpoilerPaintingContext( layer: childLayer, estimatedBounds: bounds, @@ -568,14 +590,17 @@ Offset _editablePaintOffset(RenderEditable editable) { if (pixels == 0) return Offset.zero; final isSingleLine = editable.maxLines == 1; if (isSingleLine) { - return editable.textDirection == TextDirection.rtl ? Offset(pixels, 0) : Offset(-pixels, 0); + return editable.textDirection == TextDirection.rtl + ? Offset(pixels, 0) + : Offset(-pixels, 0); } return Offset(0, -pixels); } Rect _normalizeEditableRect(Rect rect, RenderEditable editable) { final minHeight = editable.preferredLineHeight; - const double leftPadding = 2.0; // cover leading-side clipping (e.g., descenders at start) + const double leftPadding = + 2.0; // cover leading-side clipping (e.g., descenders at start) return Rect.fromLTRB( rect.left - leftPadding, rect.top, @@ -597,7 +622,8 @@ class SpoilerCanvas implements Canvas { if (context.calculateRects) { var currentOffset = 0; while (true) { - final range = paragraph.getWordBoundary(ui.TextPosition(offset: currentOffset)); + final range = + paragraph.getWordBoundary(ui.TextPosition(offset: currentOffset)); if (range.start == range.end) break; final fullText = context.currentText ?? ''; @@ -650,20 +676,25 @@ class SpoilerCanvas implements Canvas { @override Float64List getTransform() => parent.getTransform(); @override - void clipRect(Rect rect, {ui.ClipOp clipOp = ui.ClipOp.intersect, bool doAntiAlias = true}) => + void clipRect(Rect rect, + {ui.ClipOp clipOp = ui.ClipOp.intersect, bool doAntiAlias = true}) => parent.clipRect(rect, clipOp: clipOp, doAntiAlias: doAntiAlias); @override - void clipRRect(RRect rrect, {bool doAntiAlias = true}) => parent.clipRRect(rrect, doAntiAlias: doAntiAlias); + void clipRRect(RRect rrect, {bool doAntiAlias = true}) => + parent.clipRRect(rrect, doAntiAlias: doAntiAlias); @override - void clipPath(Path path, {bool doAntiAlias = true}) => parent.clipPath(path, doAntiAlias: doAntiAlias); + void clipPath(Path path, {bool doAntiAlias = true}) => + parent.clipPath(path, doAntiAlias: doAntiAlias); @override Rect getLocalClipBounds() => parent.getLocalClipBounds(); @override Rect getDestinationClipBounds() => parent.getDestinationClipBounds(); @override - void drawColor(Color color, BlendMode blendMode) => parent.drawColor(color, blendMode); + void drawColor(Color color, BlendMode blendMode) => + parent.drawColor(color, blendMode); @override - void drawLine(Offset p1, Offset p2, Paint paint) => parent.drawLine(p1, p2, paint); + void drawLine(Offset p1, Offset p2, Paint paint) => + parent.drawLine(p1, p2, paint); @override void drawPaint(Paint paint) => parent.drawPaint(paint); @override @@ -671,20 +702,25 @@ class SpoilerCanvas implements Canvas { @override void drawRRect(RRect rrect, Paint paint) => parent.drawRRect(rrect, paint); @override - void drawDRRect(RRect outer, RRect inner, Paint paint) => parent.drawDRRect(outer, inner, paint); + void drawDRRect(RRect outer, RRect inner, Paint paint) => + parent.drawDRRect(outer, inner, paint); @override void drawOval(Rect rect, Paint paint) => parent.drawOval(rect, paint); @override - void drawCircle(Offset c, double radius, Paint paint) => parent.drawCircle(c, radius, paint); + void drawCircle(Offset c, double radius, Paint paint) => + parent.drawCircle(c, radius, paint); @override - void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) => + void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, + Paint paint) => parent.drawArc(rect, startAngle, sweepAngle, useCenter, paint); @override void drawPath(Path path, Paint paint) => parent.drawPath(path, paint); @override - void drawImage(ui.Image image, Offset p, Paint paint) => parent.drawImage(image, p, paint); + void drawImage(ui.Image image, Offset p, Paint paint) => + parent.drawImage(image, p, paint); @override - void drawImageRect(ui.Image image, Rect src, Rect dst, Paint paint) => parent.drawImageRect(image, src, dst, paint); + void drawImageRect(ui.Image image, Rect src, Rect dst, Paint paint) => + parent.drawImageRect(image, src, dst, paint); @override void drawImageNine(ui.Image image, Rect center, Rect dst, Paint paint) => parent.drawImageNine(image, center, dst, paint); @@ -697,15 +733,30 @@ class SpoilerCanvas implements Canvas { void drawVertices(ui.Vertices vertices, BlendMode blendMode, Paint paint) => parent.drawVertices(vertices, blendMode, paint); @override - void drawAtlas(ui.Image atlas, List transforms, List rects, List? colors, - BlendMode? blendMode, Rect? cullRect, Paint paint) => - parent.drawAtlas(atlas, transforms, rects, colors, blendMode, cullRect, paint); - @override - void drawRawAtlas(ui.Image atlas, Float32List rstTransforms, Float32List rects, Int32List? colors, - BlendMode? blendMode, Rect? cullRect, Paint paint) => - parent.drawRawAtlas(atlas, rstTransforms, rects, colors, blendMode, cullRect, paint); - @override - void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) => + void drawAtlas( + ui.Image atlas, + List transforms, + List rects, + List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) => + parent.drawAtlas( + atlas, transforms, rects, colors, blendMode, cullRect, paint); + @override + void drawRawAtlas( + ui.Image atlas, + Float32List rstTransforms, + Float32List rects, + Int32List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) => + parent.drawRawAtlas( + atlas, rstTransforms, rects, colors, blendMode, cullRect, paint); + @override + void drawShadow( + Path path, Color color, double elevation, bool transparentOccluder) => parent.drawShadow(path, color, elevation, transparentOccluder); @override void drawRawPoints(ui.PointMode pointMode, Float32List points, Paint paint) => @@ -714,7 +765,8 @@ class SpoilerCanvas implements Canvas { @override void clipRSuperellipse(dynamic rsuperellipse, {bool doAntiAlias = true}) { // ignore: avoid_dynamic_calls - (parent as dynamic).clipRSuperellipse(rsuperellipse, doAntiAlias: doAntiAlias); + (parent as dynamic) + .clipRSuperellipse(rsuperellipse, doAntiAlias: doAntiAlias); } @override diff --git a/test/golden_test.dart b/test/golden_test.dart index 66b69c8..6150747 100644 --- a/test/golden_test.dart +++ b/test/golden_test.dart @@ -63,9 +63,18 @@ void main() { Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - SizedBox(width: 40, height: 40, child: ColoredBox(color: Colors.blue)), - SizedBox(width: 40, height: 40, child: ColoredBox(color: Colors.green)), - SizedBox(width: 40, height: 40, child: ColoredBox(color: Colors.orange)), + SizedBox( + width: 40, + height: 40, + child: ColoredBox(color: Colors.blue)), + SizedBox( + width: 40, + height: 40, + child: ColoredBox(color: Colors.green)), + SizedBox( + width: 40, + height: 40, + child: ColoredBox(color: Colors.orange)), ], ), SizedBox(height: 12), @@ -396,7 +405,8 @@ void _overrideGoldenTolerance(double tolerance) { Future _allowShaderLoad(WidgetTester tester) async { await tester.pump(const Duration(milliseconds: 16)); - await tester.binding.runAsync(() => Future.delayed(const Duration(milliseconds: 50))); + await tester.binding + .runAsync(() => Future.delayed(const Duration(milliseconds: 50))); await tester.pump(const Duration(milliseconds: 16)); } @@ -425,7 +435,8 @@ class _TolerantGoldenFileComparator extends LocalFileComparator { await getGoldenBytes(golden), ); - final bool passed = result.passed || result.diffPercent <= _precisionTolerance; + final bool passed = + result.passed || result.diffPercent <= _precisionTolerance; if (passed) { result.dispose(); return true; diff --git a/test/overlay_test.dart b/test/overlay_test.dart index 1479704..71e88fd 100644 --- a/test/overlay_test.dart +++ b/test/overlay_test.dart @@ -48,7 +48,8 @@ void main() { expect(states.last, isFalse); }); - testWidgets('SpoilerOverlay ignores taps when gestures are disabled', (tester) async { + testWidgets('SpoilerOverlay ignores taps when gestures are disabled', + (tester) async { final states = []; final config = WidgetSpoilerConfig( imageFilter: ImageFilter.blur(sigmaX: 1.0, sigmaY: 1.0), diff --git a/test/render_object_widget_test.dart b/test/render_object_widget_test.dart index b9c0229..0404c81 100644 --- a/test/render_object_widget_test.dart +++ b/test/render_object_widget_test.dart @@ -23,7 +23,8 @@ void main() { expect(rects, isNotEmpty); }); - testWidgets('SpoilerRenderObjectWidget reports selection rects for TextField', (tester) async { + testWidgets('SpoilerRenderObjectWidget reports selection rects for TextField', + (tester) async { final controller = TextEditingController(text: 'Hello world'); final focusNode = FocusNode(); addTearDown(controller.dispose); diff --git a/test/text_field_wrapper_test.dart b/test/text_field_wrapper_test.dart index 4cee8ea..d2ce4eb 100644 --- a/test/text_field_wrapper_test.dart +++ b/test/text_field_wrapper_test.dart @@ -6,7 +6,8 @@ import 'package:spoiler_widget/models/spoiler_configs.dart'; import 'package:spoiler_widget/spoiler_text_form_field.dart'; void main() { - testWidgets('SpoilerTextFieldWrapper adds menu item and reports selection', (tester) async { + testWidgets('SpoilerTextFieldWrapper adds menu item and reports selection', + (tester) async { final controller = TextEditingController(text: 'Secret text'); final focusNode = FocusNode(); addTearDown(controller.dispose); diff --git a/test/utils_test.dart b/test/utils_test.dart index fb5aac1..aa4e622 100644 --- a/test/utils_test.dart +++ b/test/utils_test.dart @@ -20,7 +20,8 @@ void main() { shapePreset: ParticlePathPreset.star, ); - expect(config.areaFactor, closeTo(ParticlePathPreset.star.areaFactor!, 0.0001)); + expect(config.areaFactor, + closeTo(ParticlePathPreset.star.areaFactor!, 0.0001)); }); test('ParticleConfig areaFactor computes for custom path', () { diff --git a/test/widgets_test.dart b/test/widgets_test.dart index 0ba5c2d..cabe386 100644 --- a/test/widgets_test.dart +++ b/test/widgets_test.dart @@ -5,7 +5,8 @@ import 'package:spoiler_widget/models/text_spoiler_configs.dart'; import 'package:spoiler_widget/spoiler_text_wrapper.dart'; void main() { - testWidgets('SpoilerTextWrapper toggles via tap when gestures enabled', (tester) async { + testWidgets('SpoilerTextWrapper toggles via tap when gestures enabled', + (tester) async { bool? lastVisibility; final config = TextSpoilerConfig( isEnabled: true, @@ -39,7 +40,8 @@ void main() { expect(lastVisibility, isFalse); }); - testWidgets('SpoilerTextWrapper ignores tap when gestures disabled', (tester) async { + testWidgets('SpoilerTextWrapper ignores tap when gestures disabled', + (tester) async { bool? lastVisibility; final config = TextSpoilerConfig( isEnabled: true,