From 86da33b70c048f623ff95b9a4434f471eff60ac1 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 19:08:54 +0800 Subject: [PATCH 1/4] use fake glass on android fixes severe rendering bugs --- .../lib/v2/components/liquid_glass_base.dart | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/mobile-app/lib/v2/components/liquid_glass_base.dart b/mobile-app/lib/v2/components/liquid_glass_base.dart index 4fd99854..d2e2efb1 100644 --- a/mobile-app/lib/v2/components/liquid_glass_base.dart +++ b/mobile-app/lib/v2/components/liquid_glass_base.dart @@ -1,3 +1,4 @@ +import 'dart:io' show Platform; import 'package:flutter/material.dart'; import 'package:liquid_glass_renderer/liquid_glass_renderer.dart'; @@ -30,31 +31,28 @@ class LiquidGlassBase extends StatelessWidget { }) : shape = Shape.circular, radius = 100.0; + LiquidGlassSettings get _settings => LiquidGlassSettings( + glassColor: glassColor, + visibility: visibility, + thickness: 20, + blur: 4, + refractiveIndex: 1.33, + lightAngle: 45 * (3.1416 / 180), + lightIntensity: 0.5, + ambientStrength: -0.2, + saturation: 1.5, + ); + @override Widget build(BuildContext context) { - return LiquidGlassLayer( - settings: LiquidGlassSettings( - glassColor: glassColor, - visibility: visibility, - thickness: 20, - blur: 4, - refractiveIndex: 1.33, - lightAngle: 45 * (3.1416 / 180), - lightIntensity: 0.5, - ambientStrength: -0.2, - saturation: 1.5, - ), - child: centered - ? Center( - child: LiquidGlass( - shape: LiquidRoundedSuperellipse(borderRadius: radius), - child: child, - ), - ) - : LiquidGlass( - shape: LiquidRoundedSuperellipse(borderRadius: radius), - child: child, - ), - ); + final glassShape = LiquidRoundedSuperellipse(borderRadius: radius); + final Widget glass = Platform.isAndroid + ? FakeGlass(settings: _settings, shape: glassShape, child: child) + : LiquidGlassLayer( + settings: _settings, + child: LiquidGlass(shape: glassShape, child: child), + ); + + return centered ? Center(child: glass) : glass; } } From 0a5109bb44a4db13edd998be5445cc7296ca8675 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 19:38:25 +0800 Subject: [PATCH 2/4] fix for android fake glass took fake glass rendering out of the liquid_glass_package, put it into our own file so we can use it. format code --- .../lib/services/local_auth_service.dart | 6 +- .../lib/v2/components/android_glass.dart | 130 ++++++++++++++++++ .../lib/v2/components/liquid_glass_base.dart | 29 ++-- 3 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 mobile-app/lib/v2/components/android_glass.dart diff --git a/mobile-app/lib/services/local_auth_service.dart b/mobile-app/lib/services/local_auth_service.dart index cdfee453..50287eeb 100644 --- a/mobile-app/lib/services/local_auth_service.dart +++ b/mobile-app/lib/services/local_auth_service.dart @@ -45,11 +45,7 @@ class LocalAuthService { final didAuthenticate = await _localAuth.authenticate( localizedReason: localizedReason, - options: const AuthenticationOptions( - biometricOnly: false, - stickyAuth: true, - sensitiveTransaction: true, - ), + options: const AuthenticationOptions(biometricOnly: false, stickyAuth: true, sensitiveTransaction: true), ); if (didAuthenticate) cleanLastPausedTime(); diff --git a/mobile-app/lib/v2/components/android_glass.dart b/mobile-app/lib/v2/components/android_glass.dart new file mode 100644 index 00000000..5ab3ad1b --- /dev/null +++ b/mobile-app/lib/v2/components/android_glass.dart @@ -0,0 +1,130 @@ +import 'dart:math' as math; +import 'dart:ui' as ui; +import 'package:flutter/material.dart'; + +class AndroidGlass extends StatelessWidget { + final double visibility; + final Color glassColor; + final double radius; + final double lightIntensity; + final double lightAngle; + final double thickness; + final double ambientStrength; + final bool centered; + final Widget child; + + const AndroidGlass({ + super.key, + required this.child, + this.visibility = 1.0, + this.glassColor = const Color(0x1AFFFFFF), + this.radius = 14.0, + this.lightIntensity = 0.5, + this.lightAngle = 45 * (3.1416 / 180), + this.thickness = 20.0, + this.ambientStrength = 0.0, + this.centered = true, + }); + + @override + Widget build(BuildContext context) { + Widget glass = ClipRRect( + borderRadius: BorderRadius.circular(radius), + child: CustomPaint( + foregroundPainter: _SpecularPainter( + radius: radius, + lightIntensity: lightIntensity * visibility, + lightAngle: lightAngle, + thickness: thickness * visibility, + ambientStrength: ambientStrength, + ), + child: DecoratedBox( + decoration: BoxDecoration(color: glassColor), + child: child, + ), + ), + ); + + if (visibility < 1.0) glass = Opacity(opacity: visibility, child: glass); + return centered ? Center(child: glass) : glass; + } +} + +class _SpecularPainter extends CustomPainter { + final double radius; + final double lightIntensity; + final double lightAngle; + final double thickness; + final double ambientStrength; + + const _SpecularPainter({ + required this.radius, + required this.lightIntensity, + required this.lightAngle, + required this.thickness, + required this.ambientStrength, + }); + + @override + void paint(Canvas canvas, Size size) { + final path = Path()..addRRect(RRect.fromRectAndRadius(Offset.zero & size, Radius.circular(radius))); + final bounds = Offset.zero & size; + final squareBounds = Rect.fromCircle(center: bounds.center, radius: bounds.size.longestSide / 2); + + final intensity = lightIntensity.clamp(0.0, 1.0); + final thicknessFactor = (thickness / 5).clamp(0.0, 1.0); + final alpha = Curves.easeOut.transform(intensity); + final color = Colors.white.withValues(alpha: alpha * thicknessFactor); + + final x = math.cos(lightAngle); + final y = math.sin(lightAngle); + + final lightCoverage = ui.lerpDouble(.3, .5, intensity)!; + final alignmentWithShortestSide = (size.aspectRatio < 1 ? y : x).abs(); + final aspectAdjustment = 1 - 1 / size.aspectRatio; + final gradientScale = aspectAdjustment * (1 - alignmentWithShortestSide); + final inset = ui.lerpDouble(0, .5, gradientScale.clamp(0, 1))!; + final secondInset = ui.lerpDouble(lightCoverage, .5, gradientScale.clamp(0, 1))!; + + final shader = LinearGradient( + colors: [ + color, + color.withValues(alpha: ambientStrength), + color.withValues(alpha: ambientStrength), + color, + ], + stops: [inset, secondInset, 1 - secondInset, 1 - inset], + begin: Alignment(x, y), + end: Alignment(-x, -y), + ).createShader(squareBounds); + + canvas.drawPath( + path, + Paint() + ..shader = shader + ..style = PaintingStyle.stroke + ..strokeWidth = ui.lerpDouble(1, 2, intensity)! + ..color = color.withValues(alpha: color.a * 0.3) + ..blendMode = BlendMode.hardLight, + ); + + canvas.drawPath( + path, + Paint() + ..shader = shader + ..style = PaintingStyle.stroke + ..maskFilter = MaskFilter.blur(BlurStyle.normal, thickness / 40) + ..strokeWidth = thickness / 10 + ..color = color.withValues(alpha: color.a * 0.6) + ..blendMode = BlendMode.overlay, + ); + } + + @override + bool shouldRepaint(_SpecularPainter old) => + radius != old.radius || + lightIntensity != old.lightIntensity || + lightAngle != old.lightAngle || + thickness != old.thickness || + ambientStrength != old.ambientStrength; +} diff --git a/mobile-app/lib/v2/components/liquid_glass_base.dart b/mobile-app/lib/v2/components/liquid_glass_base.dart index d2e2efb1..e8fd576c 100644 --- a/mobile-app/lib/v2/components/liquid_glass_base.dart +++ b/mobile-app/lib/v2/components/liquid_glass_base.dart @@ -1,6 +1,7 @@ import 'dart:io' show Platform; import 'package:flutter/material.dart'; import 'package:liquid_glass_renderer/liquid_glass_renderer.dart'; +import 'package:resonance_network_wallet/v2/components/android_glass.dart'; enum Shape { rounded, circular } @@ -45,14 +46,24 @@ class LiquidGlassBase extends StatelessWidget { @override Widget build(BuildContext context) { - final glassShape = LiquidRoundedSuperellipse(borderRadius: radius); - final Widget glass = Platform.isAndroid - ? FakeGlass(settings: _settings, shape: glassShape, child: child) - : LiquidGlassLayer( - settings: _settings, - child: LiquidGlass(shape: glassShape, child: child), - ); - - return centered ? Center(child: glass) : glass; + final settings = _settings; + if (Platform.isAndroid) { + return AndroidGlass( + visibility: settings.visibility, + glassColor: settings.glassColor == Colors.transparent ? const Color(0x1AFFFFFF) : glassColor, + radius: radius, + centered: centered, + child: child, + ); + } else { + Widget glass = LiquidGlassLayer( + settings: settings, + child: LiquidGlass( + shape: LiquidRoundedSuperellipse(borderRadius: radius), + child: child, + ), + ); + return centered ? Center(child: glass) : glass; + } } } From 7e46efea4a36f03b17a82588fb87a36bab748396 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 20:38:01 +0800 Subject: [PATCH 3/4] make iOS case same code as before --- .../lib/v2/components/liquid_glass_base.dart | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/mobile-app/lib/v2/components/liquid_glass_base.dart b/mobile-app/lib/v2/components/liquid_glass_base.dart index e8fd576c..d728ee0e 100644 --- a/mobile-app/lib/v2/components/liquid_glass_base.dart +++ b/mobile-app/lib/v2/components/liquid_glass_base.dart @@ -56,14 +56,20 @@ class LiquidGlassBase extends StatelessWidget { child: child, ); } else { - Widget glass = LiquidGlassLayer( + return LiquidGlassLayer( settings: settings, - child: LiquidGlass( - shape: LiquidRoundedSuperellipse(borderRadius: radius), - child: child, - ), + child: centered + ? Center( + child: LiquidGlass( + shape: LiquidRoundedSuperellipse(borderRadius: radius), + child: child, + ), + ) + : LiquidGlass( + shape: LiquidRoundedSuperellipse(borderRadius: radius), + child: child, + ), ); - return centered ? Center(child: glass) : glass; } } } From ffb4fd2e0352cdb5344ecaad2c3cc49979535d0d Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 20:42:23 +0800 Subject: [PATCH 4/4] DRY violation fix --- .../lib/v2/components/liquid_glass_base.dart | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/mobile-app/lib/v2/components/liquid_glass_base.dart b/mobile-app/lib/v2/components/liquid_glass_base.dart index d728ee0e..5f35e447 100644 --- a/mobile-app/lib/v2/components/liquid_glass_base.dart +++ b/mobile-app/lib/v2/components/liquid_glass_base.dart @@ -56,19 +56,13 @@ class LiquidGlassBase extends StatelessWidget { child: child, ); } else { + var liquidGlass = LiquidGlass( + shape: LiquidRoundedSuperellipse(borderRadius: radius), + child: child, + ); return LiquidGlassLayer( settings: settings, - child: centered - ? Center( - child: LiquidGlass( - shape: LiquidRoundedSuperellipse(borderRadius: radius), - child: child, - ), - ) - : LiquidGlass( - shape: LiquidRoundedSuperellipse(borderRadius: radius), - child: child, - ), + child: centered ? Center(child: liquidGlass) : liquidGlass, ); } }