打包:版本发布

This commit is contained in:
ivan 2026-03-15 12:02:36 +08:00
parent 066d8b7391
commit 596fe05e09
10 changed files with 47 additions and 40 deletions

View File

@ -138,8 +138,8 @@ class _GalleryScreenState extends State<GalleryScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: AppColors.background, backgroundColor: AppColors.background,
appBar: PreferredSize( appBar: const PreferredSize(
preferredSize: const Size.fromHeight(56), preferredSize: Size.fromHeight(56),
child: TopNavBar( child: TopNavBar(
title: 'My Gallery', title: 'My Gallery',
), ),
@ -154,7 +154,7 @@ class _GalleryScreenState extends State<GalleryScreen> {
Text( Text(
_error!, _error!,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(color: AppColors.textSecondary), style: const TextStyle(color: AppColors.textSecondary),
), ),
const SizedBox(height: AppSpacing.lg), const SizedBox(height: AppSpacing.lg),
TextButton( TextButton(
@ -177,7 +177,7 @@ class _GalleryScreenState extends State<GalleryScreen> {
const AlwaysScrollableScrollPhysics(), const AlwaysScrollableScrollPhysics(),
child: SizedBox( child: SizedBox(
height: constraints.maxHeight - 100, height: constraints.maxHeight - 100,
child: Center( child: const Center(
child: Text( child: Text(
'No images yet', 'No images yet',
style: TextStyle( style: TextStyle(
@ -264,11 +264,11 @@ class _GalleryCard extends StatelessWidget {
color: AppColors.surfaceAlt, color: AppColors.surfaceAlt,
borderRadius: BorderRadius.circular(24), borderRadius: BorderRadius.circular(24),
border: Border.all(color: AppColors.border, width: 1), border: Border.all(color: AppColors.border, width: 1),
boxShadow: [ boxShadow: const [
BoxShadow( BoxShadow(
color: AppColors.shadowMedium, color: AppColors.shadowMedium,
blurRadius: 12, blurRadius: 12,
offset: const Offset(0, 4), offset: Offset(0, 4),
), ),
], ],
), ),
@ -276,7 +276,8 @@ class _GalleryCard extends StatelessWidget {
borderRadius: BorderRadius.circular(24), borderRadius: BorderRadius.circular(24),
child: mediaItem.isVideo child: mediaItem.isVideo
? _VideoThumbnailCover(videoUrl: mediaItem.videoUrl!) ? _VideoThumbnailCover(videoUrl: mediaItem.videoUrl!)
: (mediaItem.imageUrl != null && mediaItem.imageUrl!.isNotEmpty) : (mediaItem.imageUrl != null &&
mediaItem.imageUrl!.isNotEmpty)
? CachedNetworkImage( ? CachedNetworkImage(
imageUrl: mediaItem.imageUrl!, imageUrl: mediaItem.imageUrl!,
fit: BoxFit.cover, fit: BoxFit.cover,

View File

@ -232,7 +232,7 @@ class _VideoPreview extends StatelessWidget {
: Column( : Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon( const Icon(
LucideIcons.film, LucideIcons.film,
size: 64, size: 64,
color: AppColors.textSecondary, color: AppColors.textSecondary,

View File

@ -323,7 +323,7 @@ class _CreditsCard extends StatelessWidget {
), ),
child: Row( child: Row(
children: [ children: [
Icon(LucideIcons.sparkles, size: 28, color: AppColors.surface), const Icon(LucideIcons.sparkles, size: 28, color: AppColors.surface),
const SizedBox(width: AppSpacing.md), const SizedBox(width: AppSpacing.md),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -495,14 +495,15 @@ class _VideoPreviewAreaState extends State<_VideoPreviewArea> {
fit: BoxFit.contain, fit: BoxFit.contain,
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
placeholder: (_, __) => _LoadingOverlay(isLoading: true), placeholder: (_, __) =>
const _LoadingOverlay(isLoading: true),
errorWidget: (_, __, ___) => errorWidget: (_, __, ___) =>
_LoadingOverlay(isLoading: false), const _LoadingOverlay(isLoading: false),
) )
else else
_LoadingOverlay(isLoading: false), const _LoadingOverlay(isLoading: false),
if (hasVideo && !isReady) if (hasVideo && !isReady)
Positioned.fill( const Positioned.fill(
child: _LoadingOverlay(isLoading: true), child: _LoadingOverlay(isLoading: true),
), ),
], ],
@ -590,12 +591,12 @@ class _AspectRatioImageState extends State<_AspectRatioImage> {
placeholder: (_, __) => SizedBox( placeholder: (_, __) => SizedBox(
width: widget.maxWidth, width: widget.maxWidth,
height: widget.maxWidth, height: widget.maxWidth,
child: _LoadingOverlay(isLoading: true), child: const _LoadingOverlay(isLoading: true),
), ),
errorWidget: (_, __, ___) => SizedBox( errorWidget: (_, __, ___) => SizedBox(
width: widget.maxWidth, width: widget.maxWidth,
height: widget.maxWidth, height: widget.maxWidth,
child: _LoadingOverlay(isLoading: false), child: const _LoadingOverlay(isLoading: false),
), ),
), ),
); );
@ -621,7 +622,7 @@ class _LoadingOverlay extends StatelessWidget {
color: AppColors.primary, color: AppColors.primary,
), ),
) )
: Icon( : const Icon(
LucideIcons.video, LucideIcons.video,
size: 48, size: 48,
color: AppColors.textMuted, color: AppColors.textMuted,
@ -785,7 +786,7 @@ class _GenerateButton extends StatelessWidget {
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( const Icon(
LucideIcons.sparkles, LucideIcons.sparkles,
size: 16, size: 16,
color: AppColors.surface, color: AppColors.surface,

View File

@ -136,7 +136,7 @@ class _GenerationResultScreenState extends State<GenerationResultScreen> {
), ),
), ),
body: widget.mediaItem == null body: widget.mediaItem == null
? Center( ? const Center(
child: Text( child: Text(
'No media', 'No media',
style: TextStyle(color: AppColors.textSecondary), style: TextStyle(color: AppColors.textSecondary),
@ -208,7 +208,7 @@ class _MediaDisplay extends StatelessWidget {
? Container( ? Container(
color: AppColors.textPrimary, color: AppColors.textPrimary,
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: const Text(
'Load failed', 'Load failed',
style: TextStyle(color: AppColors.surface), style: TextStyle(color: AppColors.surface),
), ),
@ -377,7 +377,8 @@ class _DownloadButton extends StatelessWidget {
), ),
) )
else else
Icon(LucideIcons.download, size: 20, color: AppColors.surface), const Icon(LucideIcons.download,
size: 20, color: AppColors.surface),
const SizedBox(width: AppSpacing.md), const SizedBox(width: AppSpacing.md),
Text( Text(
saving ? 'Saving...' : 'Save to Album', saving ? 'Saving...' : 'Save to Album',
@ -407,18 +408,18 @@ class _ShareButton extends StatelessWidget {
color: AppColors.surface, color: AppColors.surface,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(14),
border: Border.all(color: AppColors.border), border: Border.all(color: AppColors.border),
boxShadow: [ boxShadow: const [
BoxShadow( BoxShadow(
color: AppColors.shadowLight, color: AppColors.shadowLight,
blurRadius: 6, blurRadius: 6,
offset: const Offset(0, 2), offset: Offset(0, 2),
), ),
], ],
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(LucideIcons.share_2, size: 20, color: AppColors.primary), const Icon(LucideIcons.share_2, size: 20, color: AppColors.primary),
const SizedBox(width: AppSpacing.md), const SizedBox(width: AppSpacing.md),
Text( Text(
'Share', 'Share',

View File

@ -144,11 +144,11 @@ class _VideoCardState extends State<VideoCard> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.transparent, color: Colors.transparent,
borderRadius: BorderRadius.circular(24), borderRadius: BorderRadius.circular(24),
boxShadow: [ boxShadow: const [
BoxShadow( BoxShadow(
color: AppColors.shadowMedium, color: AppColors.shadowMedium,
blurRadius: 12, blurRadius: 12,
offset: const Offset(0, 4), offset: Offset(0, 4),
), ),
], ],
), ),
@ -213,7 +213,7 @@ class _VideoCardState extends State<VideoCard> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon( const Icon(
LucideIcons.sparkles, LucideIcons.sparkles,
size: 12, size: 12,
color: AppColors.surface, color: AppColors.surface,
@ -273,11 +273,11 @@ class _VideoCardState extends State<VideoCard> {
color: AppColors.primary, color: AppColors.primary,
width: 1, width: 1,
), ),
boxShadow: [ boxShadow: const [
BoxShadow( BoxShadow(
color: AppColors.primaryButtonShadow, color: AppColors.primaryButtonShadow,
blurRadius: 6, blurRadius: 6,
offset: const Offset(0, 2), offset: Offset(0, 2),
), ),
], ],
), ),

View File

@ -8,7 +8,6 @@ import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:pets_hero_ai/core/api/api.dart'; import 'package:pets_hero_ai/core/api/api.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../../core/api/services/payment_api.dart';
import '../../core/log/app_logger.dart'; import '../../core/log/app_logger.dart';
import '../../core/user/account_refresh.dart'; import '../../core/user/account_refresh.dart';
import '../../core/user/user_state.dart'; import '../../core/user/user_state.dart';
@ -232,13 +231,15 @@ abstract final class GooglePlayPurchaseService {
/// completePurchase Android consumePurchaseautoConsume: false /// completePurchase Android consumePurchaseautoConsume: false
/// [GooglePayPurchaseResult.purchaseDetails] /// [GooglePayPurchaseResult.purchaseDetails]
static Future<bool> completeAndConsumePurchase(PurchaseDetails purchaseDetails) async { static Future<bool> completeAndConsumePurchase(
PurchaseDetails purchaseDetails) async {
final iap = InAppPurchase.instance; final iap = InAppPurchase.instance;
try { try {
iap.completePurchase(purchaseDetails); iap.completePurchase(purchaseDetails);
_log.d('completePurchase 已执行'); _log.d('completePurchase 已执行');
if (defaultTargetPlatform == TargetPlatform.android) { if (defaultTargetPlatform == TargetPlatform.android) {
final androidAddition = iap.getPlatformAddition<InAppPurchaseAndroidPlatformAddition>(); final androidAddition =
iap.getPlatformAddition<InAppPurchaseAndroidPlatformAddition>();
final result = await androidAddition.consumePurchase(purchaseDetails); final result = await androidAddition.consumePurchase(purchaseDetails);
final ok = result.responseCode == BillingResponse.ok; final ok = result.responseCode == BillingResponse.ok;
if (ok) { if (ok) {
@ -256,7 +257,8 @@ abstract final class GooglePlayPurchaseService {
} }
/// completePurchase + consumePurchase /// completePurchase + consumePurchase
static Future<bool> _consumePurchase(InAppPurchase iap, UnacknowledgedGooglePayPurchase p) async { static Future<bool> _consumePurchase(
InAppPurchase iap, UnacknowledgedGooglePayPurchase p) async {
return completeAndConsumePurchase(p.purchaseDetails); return completeAndConsumePurchase(p.purchaseDetails);
} }
@ -294,7 +296,8 @@ abstract final class GooglePlayPurchaseService {
final line = (data?['line']?.toString() ?? '').toUpperCase(); final line = (data?['line']?.toString() ?? '').toUpperCase();
final status = (data?['status']?.toString() ?? '').toUpperCase(); final status = (data?['status']?.toString() ?? '').toUpperCase();
final isSuccess = line == 'SUCCESS' || status == 'SUCCESS'; final isSuccess = line == 'SUCCESS' || status == 'SUCCESS';
_log.d('补单响应 orderId=${p.orderId} data=$data line=$line status=$status isSuccess=$isSuccess'); _log.d(
'补单响应 orderId=${p.orderId} data=$data line=$line status=$status isSuccess=$isSuccess');
if (isSuccess) { if (isSuccess) {
if (await _consumePurchase(iap, p)) { if (await _consumePurchase(iap, p)) {
_pendingFromStream.remove(p.orderId); _pendingFromStream.remove(p.orderId);

View File

@ -27,13 +27,13 @@ class BottomNavBar extends StatelessWidget {
horizontal: AppSpacing.screenPadding, horizontal: AppSpacing.screenPadding,
vertical: 7.5, vertical: 7.5,
), ),
decoration: BoxDecoration( decoration: const BoxDecoration(
color: AppColors.surface, color: AppColors.surface,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: AppColors.shadowSoft, color: AppColors.shadowSoft,
blurRadius: 12, blurRadius: 12,
offset: const Offset(0, -4), offset: Offset(0, -4),
), ),
], ],
), ),

View File

@ -38,7 +38,8 @@ class CreditsBadge extends StatelessWidget {
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon(LucideIcons.sparkles, size: 16, color: AppColors.primary), const Icon(LucideIcons.sparkles,
size: 16, color: AppColors.primary),
const SizedBox(width: AppSpacing.sm), const SizedBox(width: AppSpacing.sm),
Text( Text(
credits, credits,

View File

@ -30,13 +30,13 @@ class TopNavBar extends StatelessWidget implements PreferredSizeWidget {
return Container( return Container(
height: 56, height: 56,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.screenPadding), padding: const EdgeInsets.symmetric(horizontal: AppSpacing.screenPadding),
decoration: BoxDecoration( decoration: const BoxDecoration(
color: AppColors.surface, color: AppColors.surface,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: AppColors.shadowLight, color: AppColors.shadowLight,
blurRadius: 8, blurRadius: 8,
offset: const Offset(0, 2), offset: Offset(0, 2),
), ),
], ],
), ),
@ -46,7 +46,7 @@ class TopNavBar extends StatelessWidget implements PreferredSizeWidget {
GestureDetector( GestureDetector(
onTap: onBack ?? () => Navigator.of(context).pop(), onTap: onBack ?? () => Navigator.of(context).pop(),
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: SizedBox( child: const SizedBox(
width: 40, width: 40,
height: 40, height: 40,
child: Center( child: Center(

View File

@ -1,7 +1,7 @@
name: pets_hero_ai name: pets_hero_ai
description: PetsHero AI Application. description: PetsHero AI Application.
publish_to: 'none' publish_to: 'none'
version: 1.0.3+4 version: 1.0.4+5
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'