From 07a047f031747cf1e98666242f381d2d1d815951 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 19 Apr 2026 18:03:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E6=A0=8F=E5=8A=9F=E8=83=BD=E7=A7=BB=E5=8A=A8=E5=88=B0=E9=A1=B6?= =?UTF-8?q?=E9=83=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- desgin/funymee_home.pen | 145 +++++--------------- lib/app.dart | 2 + lib/core/auth/auth_service.dart | 5 +- lib/core/funymee_route_observer.dart | 5 + lib/core/user/user_state.dart | 5 +- lib/features/history/history_screen.dart | 9 +- lib/features/home/home_screen.dart | 164 +++++++++++++++++++++-- lib/features/profile/profile_screen.dart | 46 ++++--- lib/features/shell/main_screen.dart | 92 +------------ lib/widgets/pencil_chrome.dart | 132 ++++++++++++------ pubspec.yaml | 2 +- 11 files changed, 325 insertions(+), 282 deletions(-) create mode 100644 lib/core/funymee_route_observer.dart diff --git a/desgin/funymee_home.pen b/desgin/funymee_home.pen index 5b17c1a..4b3a5f1 100644 --- a/desgin/funymee_home.pen +++ b/desgin/funymee_home.pen @@ -162,94 +162,6 @@ } ] }, - { - "type": "frame", - "id": "NV7Kd", - "name": "tabRow", - "width": "fill_container", - "fill": "#00000000", - "gap": 14, - "padding": [ - 6, - 0, - 16, - 0 - ], - "justifyContent": "center", - "alignItems": "center", - "children": [ - { - "type": "text", - "id": "douq8", - "name": "t1", - "fill": "#FFFFFF", - "content": "Dance", - "fontFamily": "Inter", - "fontSize": 15, - "fontWeight": "700" - }, - { - "type": "text", - "id": "NKz0E", - "name": "d1", - "fill": "#FFFFFF66", - "content": "|", - "fontFamily": "Inter", - "fontSize": 14, - "fontWeight": "normal" - }, - { - "type": "text", - "id": "AZTis", - "name": "t2", - "fill": "#FFFFFF", - "content": "Dress", - "fontFamily": "Inter", - "fontSize": 15, - "fontWeight": "700" - }, - { - "type": "text", - "id": "Nh9EQ", - "name": "d2", - "fill": "#FFFFFF66", - "content": "|", - "fontFamily": "Inter", - "fontSize": 14, - "fontWeight": "normal" - }, - { - "type": "text", - "id": "H8vvk", - "name": "t3", - "fill": "#FFFFFF", - "content": "Bottle", - "fontFamily": "Inter", - "fontSize": 15, - "fontWeight": "700" - }, - { - "type": "text", - "id": "DvuJh", - "name": "d3", - "fill": "#FFFFFF66", - "content": "|", - "fontFamily": "Inter", - "fontSize": 14, - "fontWeight": "normal" - }, - { - "type": "text", - "id": "RDOkw", - "name": "t4", - "fill": "#FFFFFF", - "content": "Photo Repair", - "fontFamily": "Inter", - "fontSize": 15, - "fontWeight": "700" - } - ] - }, { "type": "frame", "id": "3lNJT", @@ -272,8 +184,9 @@ "type": "frame", "id": "aHMps", "name": "createBtn", - "width": 212, - "height": 50, + "opacity": 0.88, + "width": 186, + "height": 42, "fill": { "type": "gradient", "gradientType": "linear", @@ -313,10 +226,10 @@ }, "blur": 28 }, - "gap": 12, + "gap": 10, "padding": [ - 14, - 28 + 11, + 22 ], "justifyContent": "center", "alignItems": "center", @@ -325,8 +238,8 @@ "type": "frame", "id": "TAocZ", "name": "plusCirc", - "width": 28, - "height": 28, + "width": 24, + "height": 24, "fill": "#FFFFFF", "cornerRadius": 20, "stroke": { @@ -351,8 +264,8 @@ "type": "icon_font", "id": "9PFVT", "name": "plusIc", - "width": 14, - "height": 14, + "width": 12, + "height": 12, "iconFontName": "plus", "iconFontFamily": "lucide", "fill": "#B45309" @@ -366,7 +279,7 @@ "fill": "#1C1917", "content": "Create Now", "fontFamily": "Inter", - "fontSize": 18, + "fontSize": 16, "fontWeight": "800", "letterSpacing": 0.4 } @@ -487,21 +400,27 @@ { "type": "frame", "id": "rULLj", - "name": "backF", + "name": "closeF", "width": 44, "height": 44, - "fill": "#00000000", + "fill": "#FFFFFF", + "cornerRadius": 14, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E7E5E4" + }, "justifyContent": "center", "alignItems": "center", "children": [ { "type": "icon_font", "id": "byDOX", - "width": 28, - "height": 28, - "iconFontName": "chevron-left", + "width": 26, + "height": 26, + "iconFontName": "x", "iconFontFamily": "lucide", - "fill": "#404040" + "fill": "#374151" } ] }, @@ -1077,21 +996,27 @@ { "type": "frame", "id": "dYND0", - "name": "backCr", + "name": "closeCr", "width": 44, "height": 44, - "fill": "#00000000", + "fill": "#FFFFFF", + "cornerRadius": 14, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E7E5E4" + }, "justifyContent": "center", "alignItems": "center", "children": [ { "type": "icon_font", "id": "nh3Nf", - "width": 28, - "height": 28, - "iconFontName": "chevron-left", + "width": 26, + "height": 26, + "iconFontName": "x", "iconFontFamily": "lucide", - "fill": "#404040" + "fill": "#374151" } ] }, diff --git a/lib/app.dart b/lib/app.dart index 5d20b2d..b1e3b5b 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'core/auth/auth_service.dart'; +import 'core/funymee_route_observer.dart'; import 'core/theme/app_colors.dart'; import 'core/theme/app_theme.dart'; import 'features/shell/main_screen.dart'; @@ -56,6 +57,7 @@ class _AppState extends State with WidgetsBindingObserver { title: widget.title, debugShowCheckedModeBanner: false, theme: buildFunyMeeTheme(), + navigatorObservers: [funymeeRouteObserver], home: const MainScreen(), builder: (context, child) { return Stack( diff --git a/lib/core/auth/auth_service.dart b/lib/core/auth/auth_service.dart index 375f07d..1a6d27d 100644 --- a/lib/core/auth/auth_service.dart +++ b/lib/core/auth/auth_service.dart @@ -70,7 +70,10 @@ class AppAuthCallbacks implements AuthServiceCallbacks { @override void onCommonInfoLoaded(CommonInfoResponse data) { if (data.credits != null) UserState.setCredits(data.credits!); - if (data.avatar != null) UserState.setAvatar(data.avatar!); + if (data.avatar != null) { + final t = data.avatar!.trim(); + UserState.setAvatar(t.isEmpty ? null : t); + } if (data.userName != null) UserState.setUserName(data.userName!); } diff --git a/lib/core/funymee_route_observer.dart b/lib/core/funymee_route_observer.dart new file mode 100644 index 0000000..b39e426 --- /dev/null +++ b/lib/core/funymee_route_observer.dart @@ -0,0 +1,5 @@ +import 'package:flutter/material.dart'; + +/// 供 [MaterialApp.navigatorObservers] 注册;首页视频等需在「被新路由盖住」时暂停。 +final RouteObserver> funymeeRouteObserver = + RouteObserver>(); diff --git a/lib/core/user/user_state.dart b/lib/core/user/user_state.dart index 938f02b..4de8553 100644 --- a/lib/core/user/user_state.dart +++ b/lib/core/user/user_state.dart @@ -24,7 +24,10 @@ class UserState { }) { if (userId != null) UserState.userId.value = userId; if (credits != null) UserState.credits.value = credits; - if (avatar != null) UserState.avatar.value = avatar; + if (avatar != null) { + final t = avatar.trim(); + UserState.avatar.value = t.isEmpty ? null : t; + } if (userName != null) UserState.userName.value = userName; } diff --git a/lib/features/history/history_screen.dart b/lib/features/history/history_screen.dart index 8cb36ef..9246785 100644 --- a/lib/features/history/history_screen.dart +++ b/lib/features/history/history_screen.dart @@ -127,12 +127,9 @@ class _HistoryScreenState extends State { const EdgeInsets.symmetric(horizontal: 12), child: Row( children: [ - if (widget.isRootTab) - const SizedBox(width: 44) - else - PencilRoundBackButton( - onPressed: () => Navigator.of(context).pop(), - ), + PencilRoundCloseButton( + onPressed: () => Navigator.maybePop(context), + ), Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/features/home/home_screen.dart b/lib/features/home/home_screen.dart index 0abd026..fb0d6ab 100644 --- a/lib/features/home/home_screen.dart +++ b/lib/features/home/home_screen.dart @@ -8,12 +8,15 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:video_player/video_player.dart'; import '../../core/auth/auth_service.dart'; +import '../../core/funymee_route_observer.dart'; import '../../core/open_purchase_store.dart'; import '../../core/user/user_state.dart'; import '../../core/video_file_cache.dart'; import '../../design/pencil_theme.dart'; import '../../widgets/pencil_chrome.dart'; import '../generate/generate_screen.dart'; +import '../history/history_screen.dart'; +import '../profile/profile_screen.dart'; /// 首页 Create Now 上方展示的预估积分:**480p 档**(与 [GenerateScreen] 选 480p 时一致)。 int _homeCostDisplay480p(ExtConfigItem? t) { @@ -64,6 +67,29 @@ class _HomeScreenState extends State { int _lastCategoryTabBarCount = 0; + Widget _topNavIconButton({ + required IconData icon, + required VoidCallback onTap, + }) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(8), + child: Container( + width: 35, + height: 35, + decoration: BoxDecoration( + color: const Color(0x99C4C4C4), + borderRadius: BorderRadius.circular(8), + ), + alignment: Alignment.center, + child: Icon(icon, size: 20, color: const Color(0xFF374151)), + ), + ), + ); + } + List _visibleExtItems(ExtConfigData? ext) => ext?.items.where((e) => e.isUsableOnHome).toList() ?? []; @@ -379,17 +405,46 @@ class _HomeScreenState extends State { SizedBox( height: 56, child: Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - ValueListenableBuilder( - valueListenable: UserState.credits, - builder: (_, credits, _) { - return PencilGlassCreditsPill( - amountText: credits.toStringAsFixed(2), - onTap: () => openPurchaseStore(context), + _topNavIconButton( + icon: Icons.history_rounded, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => const HistoryScreen(), + ), ); }, ), + const SizedBox(width: 8), + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ValueListenableBuilder( + valueListenable: UserState.credits, + builder: (_, credits, _) { + return PencilGlassCreditsPill( + amountText: credits.toStringAsFixed(2), + onTap: () => openPurchaseStore(context), + ); + }, + ), + const SizedBox(width: 10), + _topNavIconButton( + icon: Icons.person_rounded, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => const ProfileScreen(), + ), + ); + }, + ), + ], + ), + ), ], ), ), @@ -726,9 +781,17 @@ class _HomeItemVideoBackground extends StatefulWidget { _HomeItemVideoBackgroundState(); } -class _HomeItemVideoBackgroundState extends State<_HomeItemVideoBackground> { +class _HomeItemVideoBackgroundState extends State<_HomeItemVideoBackground> + with WidgetsBindingObserver, RouteAware { VideoPlayerController? _controller; bool _failed = false; + bool _shouldActuallyPlay = false; + bool _appInForeground = true; + + /// 首页被 [Navigator.push] 盖住时 [ModalRoute.isCurrent] 不会触发 rebuild,需靠 [RouteAware] 更新。 + bool _coveredByPushedRoute = false; + + ModalRoute? _routeAwareSubscription; /// 含 ExoPlayer 错误(416、UnrecognizedInputFormat、坏缓存等)时的自动重试次数。 static const int _maxOpenRetries = 6; @@ -744,6 +807,9 @@ class _HomeItemVideoBackgroundState extends State<_HomeItemVideoBackground> { ImageStream? _coverImageStream; ImageStreamListener? _coverImageListener; + /// [build] 中避免同一帧多次 [addPostFrameCallback]。 + bool _playbackGateCallbackPending = false; + String get _playUrl { final v = widget.item.videoUrl?.trim(); if (v != null && v.isNotEmpty) return v; @@ -753,11 +819,49 @@ class _HomeItemVideoBackgroundState extends State<_HomeItemVideoBackground> { @override void initState() { super.initState(); + WidgetsBinding.instance.addObserver(this); + final lifecycle = WidgetsBinding.instance.lifecycleState; + _appInForeground = + lifecycle == null || lifecycle == AppLifecycleState.resumed; if (widget.isActive) { _preloadCoverThenStartVideo(); } } + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + _appInForeground = state == AppLifecycleState.resumed; + unawaited(_syncPlaybackGate()); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final route = ModalRoute.of(context); + if (route != null && route != _routeAwareSubscription) { + funymeeRouteObserver.unsubscribe(this); + funymeeRouteObserver.subscribe(this, route); + _routeAwareSubscription = route; + } + } + + @override + void didPushNext() { + _coveredByPushedRoute = true; + unawaited(_syncPlaybackGate()); + } + + @override + void didPopNext() { + _coveredByPushedRoute = false; + unawaited(_syncPlaybackGate()); + // pop 当帧里 [ModalRoute.isCurrent] 往往尚未切回 true,补一帧再对齐播放状态。 + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + unawaited(_syncPlaybackGate()); + }); + } + @override void didUpdateWidget(_HomeItemVideoBackground oldWidget) { super.didUpdateWidget(oldWidget); @@ -866,6 +970,31 @@ class _HomeItemVideoBackgroundState extends State<_HomeItemVideoBackground> { } } + bool _computeShouldActuallyPlay() { + if (!mounted || !widget.isActive || !_appInForeground) return false; + if (_coveredByPushedRoute) return false; + // 是否被新路由盖住由 [RouteAware.didPushNext]/[didPopNext] 维护;勿依赖 + // [ModalRoute.isCurrent](pop 当帧常为 false 且不触发 rebuild,会导致无法 resume)。 + final tickerEnabled = TickerMode.valuesOf(context).enabled; + return tickerEnabled; + } + + Future _syncPlaybackGate() async { + final c = _controller; + if (c == null) return; + if (!c.value.isInitialized) return; + final shouldPlay = _computeShouldActuallyPlay(); + if (shouldPlay == _shouldActuallyPlay) return; + _shouldActuallyPlay = shouldPlay; + try { + if (shouldPlay) { + await c.play(); + } else { + await c.pause(); + } + } catch (_) {} + } + /// 磁盘已有有效缓存则 [VideoPlayerController.file];否则网络流式播放。 /// 仅在 [initialize] + [play] 成功后再 [downloadFile],避免并行下载把 HTML/错包写入缓存导致 UnrecognizedInputFormat。 Future _startPlaybackAsync() async { @@ -926,8 +1055,13 @@ class _HomeItemVideoBackgroundState extends State<_HomeItemVideoBackground> { _openRetries = 0; controller.setLooping(true); + _shouldActuallyPlay = _computeShouldActuallyPlay(); try { - await controller.play(); + if (_shouldActuallyPlay) { + await controller.play(); + } else { + await controller.pause(); + } } catch (_) { if (mounted) _scheduleRecoverFromError(); return; @@ -982,6 +1116,9 @@ class _HomeItemVideoBackgroundState extends State<_HomeItemVideoBackground> { @override void dispose() { + funymeeRouteObserver.unsubscribe(this); + _routeAwareSubscription = null; + WidgetsBinding.instance.removeObserver(this); _retryTimer?.cancel(); _removeCoverListener(); _disposePlayback(); @@ -1025,6 +1162,15 @@ class _HomeItemVideoBackgroundState extends State<_HomeItemVideoBackground> { @override Widget build(BuildContext context) { + final shouldPlayNow = _computeShouldActuallyPlay(); + if (shouldPlayNow != _shouldActuallyPlay && !_playbackGateCallbackPending) { + _playbackGateCallbackPending = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + _playbackGateCallbackPending = false; + if (!mounted) return; + unawaited(_syncPlaybackGate()); + }); + } if (!widget.isActive) { return SizedBox.expand( child: Stack( diff --git a/lib/features/profile/profile_screen.dart b/lib/features/profile/profile_screen.dart index 5d3b144..cfd6579 100644 --- a/lib/features/profile/profile_screen.dart +++ b/lib/features/profile/profile_screen.dart @@ -1,3 +1,4 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:client_proxy_framework/client_proxy_framework.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -9,7 +10,6 @@ import '../../core/ext_config_document_urls.dart'; import '../../core/user/user_state.dart'; import '../../design/pencil_theme.dart'; import '../../widgets/pencil_chrome.dart'; -import '../purchase/purchase_screen.dart'; import '../web/app_web_view_screen.dart'; import 'delete_account_flow.dart'; @@ -51,23 +51,12 @@ class _ProfileScreenState extends State { padding: const EdgeInsets.fromLTRB(2, 0, 14, 10), child: SizedBox( height: 56, - child: widget.isRootTab - ? Center( - child: Text( - 'Profile', - style: GoogleFonts.inter( - fontSize: 18, - fontWeight: FontWeight.w600, - color: PencilTheme.ink, - ), - ), - ) - : Align( - alignment: Alignment.centerRight, - child: PencilRoundCloseButton( - onPressed: () => Navigator.of(context).pop(), - ), - ), + child: Align( + alignment: Alignment.centerRight, + child: PencilRoundCloseButton( + onPressed: () => Navigator.maybePop(context), + ), + ), ), ), Expanded( @@ -100,12 +89,27 @@ class _ProfileScreenState extends State { builder: (context, url, _) { if (url != null && url.isNotEmpty) { return ClipOval( - child: Image.network( - url, + child: CachedNetworkImage( + imageUrl: url, fit: BoxFit.cover, width: 100, height: 100, - errorBuilder: (_, _, _) => + memCacheWidth: 200, + fadeInDuration: Duration.zero, + fadeOutDuration: Duration.zero, + placeholder: (context, url) => Center( + child: SizedBox( + width: 28, + height: 28, + child: CircularProgressIndicator( + strokeWidth: 2, + color: PencilTheme + .profileAvatarIcon + .withValues(alpha: 0.5), + ), + ), + ), + errorWidget: (context, url, error) => _avatarFallback(), ), ); diff --git a/lib/features/shell/main_screen.dart b/lib/features/shell/main_screen.dart index 7940f30..5b39678 100644 --- a/lib/features/shell/main_screen.dart +++ b/lib/features/shell/main_screen.dart @@ -1,18 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; -import '../../core/theme/app_colors.dart'; -import '../history/history_screen.dart'; import '../home/home_screen.dart'; -import '../profile/profile_screen.dart'; -/// 底栏:极淡背景渐变 + 图标/标签 [Shadow],兼顾层次与可读性。 -const List _bottomNavItemShadows = [ - Shadow(offset: Offset(0, 1), blurRadius: 3, color: Color(0x72000000)), - Shadow(offset: Offset(0, 0), blurRadius: 8, color: Color(0x40000000)), -]; - -/// Root shell: bottom tabs **Home**, **History**, **Profile** (English labels). +/// Root shell: home only (no bottom tab bar). class MainScreen extends StatefulWidget { const MainScreen({super.key}); @@ -21,88 +11,10 @@ class MainScreen extends StatefulWidget { } class _MainScreenState extends State { - int _index = 0; - @override Widget build(BuildContext context) { - final parentNav = NavigationBarTheme.of(context); return Scaffold( - // All tabs: body extends under the bottom bar (faint gradient + [NavigationBar]). - extendBody: true, - body: IndexedStack( - index: _index, - children: [ - const HomeScreen(), - HistoryScreen(isRootTab: true, isTabSelected: _index == 1), - const ProfileScreen(isRootTab: true), - ], - ), - bottomNavigationBar: Stack( - alignment: Alignment.bottomCenter, - children: [ - Positioned.fill( - child: DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [ - AppColors.surface.withValues(alpha: 0.40), - AppColors.surface.withValues(alpha: 0.15), - AppColors.surface.withValues(alpha: 0), - ], - stops: const [0.0, 0.48, 1.0], - ), - ), - ), - ), - NavigationBarTheme( - data: parentNav.copyWith( - labelTextStyle: WidgetStateProperty.resolveWith((states) { - final selected = states.contains(WidgetState.selected); - return GoogleFonts.inter( - fontSize: 12, - fontWeight: selected ? FontWeight.w600 : FontWeight.w500, - color: selected ? AppColors.primary : AppColors.onSurface, - shadows: _bottomNavItemShadows, - ); - }), - iconTheme: WidgetStateProperty.resolveWith((states) { - final selected = states.contains(WidgetState.selected); - return IconThemeData( - color: selected ? AppColors.primary : AppColors.onSurface, - shadows: _bottomNavItemShadows, - ); - }), - ), - child: NavigationBar( - backgroundColor: Colors.transparent, - elevation: 0, - surfaceTintColor: Colors.transparent, - shadowColor: Colors.transparent, - selectedIndex: _index, - onDestinationSelected: (i) => setState(() => _index = i), - destinations: const [ - NavigationDestination( - icon: Icon(Icons.home_outlined), - selectedIcon: Icon(Icons.home_rounded), - label: 'Home', - ), - NavigationDestination( - icon: Icon(Icons.history_outlined), - selectedIcon: Icon(Icons.history_rounded), - label: 'History', - ), - NavigationDestination( - icon: Icon(Icons.person_outline_rounded), - selectedIcon: Icon(Icons.person_rounded), - label: 'Profile', - ), - ], - ), - ), - ], - ), + body: const HomeScreen(), ); } } diff --git a/lib/widgets/pencil_chrome.dart b/lib/widgets/pencil_chrome.dart index 746733f..3a0e4d4 100644 --- a/lib/widgets/pencil_chrome.dart +++ b/lib/widgets/pencil_chrome.dart @@ -100,58 +100,104 @@ class PencilGlassCreditsPill extends StatelessWidget { } } -/// bi8Au Create Now:与 `desgin/funymee_home.pen` [aHMps] 一致 — 金渐变、白描边、投影。 +/// bi8Au Create Now:与 `desgin/funymee_home.pen` [aHMps] 同步(含半透明、尺寸、左加号、间距)。 class PencilCreateNowButton extends StatelessWidget { const PencilCreateNowButton({super.key, required this.onPressed}); final VoidCallback onPressed; - static const double _w = 212; - static const double _h = 50; + /// `aHMps` createBtn + static const double _w = 186; + static const double _h = 42; + + /// `aHMps` opacity + static const double _opacity = 0.88; + + /// `aHMps` gap;横向 padding 取 pen `padding` 中 22;竖直取 `(42-24)/2` 以垂直居中 24×24 左标。 + static const double _gap = 10; + static const EdgeInsets _padding = + EdgeInsets.symmetric(horizontal: 22, vertical: 9); @override Widget build(BuildContext context) { - return Material( - color: Colors.transparent, - child: InkWell( - onTap: onPressed, - borderRadius: BorderRadius.circular(999), - child: Ink( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(999), - gradient: const LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0xFFFFFDE7), - Color(0xFFFDE047), - Color(0xFFF59E0B), - ], - stops: [0.0, 0.42, 1.0], - ), - border: Border.all( - color: Color(0xD9FFFFFF), - width: 2, - ), - boxShadow: const [ - BoxShadow( - color: Color(0x52B45309), - offset: Offset(0, 10), - blurRadius: 28, + return Opacity( + opacity: _opacity, + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: onPressed, + borderRadius: BorderRadius.circular(999), + child: Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(999), + gradient: const LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0xFFFFFDE7), + Color(0xFFFDE047), + Color(0xFFF59E0B), + ], + stops: [0.0, 0.42, 1.0], ), - ], - ), - child: SizedBox( - width: _w, - height: _h, - child: Center( - child: Text( - 'Create Now', - style: GoogleFonts.inter( - fontSize: 18, - fontWeight: FontWeight.w800, - color: PencilTheme.stone900, - letterSpacing: 0.4, + border: Border.all( + color: Color(0xD9FFFFFF), + width: 2, + ), + boxShadow: const [ + BoxShadow( + color: Color(0x52B45309), + offset: Offset(0, 10), + blurRadius: 28, + ), + ], + ), + child: SizedBox( + width: _w, + height: _h, + child: Padding( + padding: _padding, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + DecoratedBox( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Color(0x99F59E0B), + width: 1.5, + ), + boxShadow: const [ + BoxShadow( + color: Color(0x14000000), + offset: Offset(0, 2), + blurRadius: 6, + ), + ], + ), + child: const SizedBox( + width: 24, + height: 24, + child: Icon( + Icons.add_rounded, + size: 12, + color: Color(0xFFB45309), + ), + ), + ), + const SizedBox(width: _gap), + Text( + 'Create Now', + style: GoogleFonts.inter( + fontSize: 16, + fontWeight: FontWeight.w800, + color: PencilTheme.stone900, + letterSpacing: 0.4, + ), + ), + ], ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index fdbb3be..1dbed90 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: funymee_ai description: "FunyMee AI Application." publish_to: 'none' -version: 1.0.14+14 +version: 1.0.15+15 environment: sdk: ^3.11.1