diff --git a/lib/core/widgets/glass_container.dart b/lib/core/widgets/glass_container.dart index 097b2ab..96af6fb 100644 --- a/lib/core/widgets/glass_container.dart +++ b/lib/core/widgets/glass_container.dart @@ -55,56 +55,61 @@ class GlassContainer extends StatelessWidget { final finalBgColor = backgroundColor ?? AppColors.glassBackground; final finalBorderColor = borderColor ?? AppColors.glassBorder; + // BackdropFilter is extremely expensive in Flutter Web on mobile Safari. + // On mobile web (width < 600), skip the blur entirely. + final screenWidth = MediaQuery.of(context).size.width; + final useBlur = blur > 0 && !(Theme.of(context).platform == TargetPlatform.iOS && screenWidth < 600); + + final inner = Container( + padding: padding, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(borderRadius), + gradient: showGradient + ? LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + finalBgColor.withOpacity(finalOpacity * 1.2), + finalBgColor.withOpacity(finalOpacity * 0.6), + ], + ) + : null, + color: showGradient ? null : finalBgColor.withOpacity(finalOpacity), + border: hasBorder + ? Border.all(color: finalBorderColor, width: borderWidth) + : null, + boxShadow: showShadow + ? [ + BoxShadow( + color: Colors.black.withOpacity(0.15), + blurRadius: 24, + spreadRadius: -6, + offset: const Offset(0, 8), + ), + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 12, + spreadRadius: -3, + offset: const Offset(0, 4), + ), + ] + : [], + ), + child: child, + ); + return Container( width: width, height: height, margin: margin, child: ClipRRect( borderRadius: BorderRadius.circular(borderRadius), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur), - child: Container( - padding: padding, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(borderRadius), - // Subtle gradient overlay for depth - gradient: showGradient - ? LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - finalBgColor.withOpacity(finalOpacity * 1.2), - finalBgColor.withOpacity(finalOpacity * 0.6), - ], - ) - : null, - border: hasBorder - ? Border.all( - color: finalBorderColor, - width: borderWidth, - ) - : null, - // Premium shadow - boxShadow: showShadow - ? [ - BoxShadow( - color: Colors.black.withOpacity(0.15), - blurRadius: 24, - spreadRadius: -6, - offset: const Offset(0, 8), - ), - BoxShadow( - color: Colors.black.withOpacity(0.08), - blurRadius: 12, - spreadRadius: -3, - offset: const Offset(0, 4), - ), - ] - : [], - ), - child: child, - ), - ), + child: useBlur + ? BackdropFilter( + filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur), + child: inner, + ) + : inner, ), ); } diff --git a/lib/mobile/widgets/mobile_scaffold.dart b/lib/mobile/widgets/mobile_scaffold.dart index d2549d9..c6e38f5 100644 --- a/lib/mobile/widgets/mobile_scaffold.dart +++ b/lib/mobile/widgets/mobile_scaffold.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'dart:ui'; import '../../core/theme/app_colors.dart'; class MobileScaffold extends ConsumerWidget { @@ -42,12 +41,9 @@ class MobileScaffold extends ConsumerWidget { child, ], ), - bottomNavigationBar: ClipRRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), - child: Container( + bottomNavigationBar: Container( decoration: BoxDecoration( - color: AppColors.surface.withOpacity(0.9), + color: AppColors.surface, border: const Border( top: BorderSide( color: AppColors.border, @@ -90,8 +86,6 @@ class MobileScaffold extends ConsumerWidget { ], ), ), - ), - ), ); } } diff --git a/web/player_mobile.html b/web/player_mobile.html index 0e662f9..13bf62c 100644 --- a/web/player_mobile.html +++ b/web/player_mobile.html @@ -15,8 +15,7 @@ -webkit-tap-highlight-color: transparent; } - html, - body { + html, body { background: #000; width: 100%; height: 100%; @@ -40,50 +39,6 @@ background: #000; } - /* Mobile-only overlay buttons */ - #mobile-on-screen-controls { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - pointer-events: none; - z-index: 10; - } - - #play-overlay { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 80px; - height: 80px; - background: rgba(0, 0, 0, 0.6); - border-radius: 50%; - display: none; - justify-content: center; - align-items: center; - pointer-events: auto; - border: 2px solid rgba(255, 255, 255, 0.3); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - z-index: 25; - transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); - } - - #play-overlay:active { - transform: translate(-50%, -50%) scale(0.9); - } - - #play-overlay svg { - width: 40px; - height: 40px; - fill: white; - margin-left: 4px; - /* Adjust for play icon alignment */ - } - - #loading { position: absolute; display: flex; @@ -105,9 +60,33 @@ } @keyframes spin { - to { - transform: rotate(360deg); - } + to { transform: rotate(360deg); } + } + + /* Unmute button — shown when iOS plays muted */ + #unmute-btn { + display: none; + position: absolute; + bottom: 32px; + left: 50%; + transform: translateX(-50%); + z-index: 30; + background: rgba(0, 0, 0, 0.75); + color: white; + border: 2px solid rgba(255, 255, 255, 0.6); + border-radius: 32px; + padding: 12px 28px; + font-size: 16px; + font-weight: 600; + letter-spacing: 0.5px; + cursor: pointer; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + pointer-events: auto; + } + + #unmute-btn:active { + background: rgba(255, 255, 255, 0.2); } #error { @@ -127,18 +106,11 @@