打包:版本发布
This commit is contained in:
parent
066d8b7391
commit
596fe05e09
@ -138,8 +138,8 @@ class _GalleryScreenState extends State<GalleryScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.background,
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(56),
|
||||
appBar: const PreferredSize(
|
||||
preferredSize: Size.fromHeight(56),
|
||||
child: TopNavBar(
|
||||
title: 'My Gallery',
|
||||
),
|
||||
@ -154,7 +154,7 @@ class _GalleryScreenState extends State<GalleryScreen> {
|
||||
Text(
|
||||
_error!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: AppColors.textSecondary),
|
||||
style: const TextStyle(color: AppColors.textSecondary),
|
||||
),
|
||||
const SizedBox(height: AppSpacing.lg),
|
||||
TextButton(
|
||||
@ -177,7 +177,7 @@ class _GalleryScreenState extends State<GalleryScreen> {
|
||||
const AlwaysScrollableScrollPhysics(),
|
||||
child: SizedBox(
|
||||
height: constraints.maxHeight - 100,
|
||||
child: Center(
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'No images yet',
|
||||
style: TextStyle(
|
||||
@ -264,11 +264,11 @@ class _GalleryCard extends StatelessWidget {
|
||||
color: AppColors.surfaceAlt,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
border: Border.all(color: AppColors.border, width: 1),
|
||||
boxShadow: [
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: AppColors.shadowMedium,
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 4),
|
||||
offset: Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -276,7 +276,8 @@ class _GalleryCard extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: mediaItem.isVideo
|
||||
? _VideoThumbnailCover(videoUrl: mediaItem.videoUrl!)
|
||||
: (mediaItem.imageUrl != null && mediaItem.imageUrl!.isNotEmpty)
|
||||
: (mediaItem.imageUrl != null &&
|
||||
mediaItem.imageUrl!.isNotEmpty)
|
||||
? CachedNetworkImage(
|
||||
imageUrl: mediaItem.imageUrl!,
|
||||
fit: BoxFit.cover,
|
||||
|
||||
@ -232,7 +232,7 @@ class _VideoPreview extends StatelessWidget {
|
||||
: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
const Icon(
|
||||
LucideIcons.film,
|
||||
size: 64,
|
||||
color: AppColors.textSecondary,
|
||||
|
||||
@ -323,7 +323,7 @@ class _CreditsCard extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(LucideIcons.sparkles, size: 28, color: AppColors.surface),
|
||||
const Icon(LucideIcons.sparkles, size: 28, color: AppColors.surface),
|
||||
const SizedBox(width: AppSpacing.md),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -495,14 +495,15 @@ class _VideoPreviewAreaState extends State<_VideoPreviewArea> {
|
||||
fit: BoxFit.contain,
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
placeholder: (_, __) => _LoadingOverlay(isLoading: true),
|
||||
placeholder: (_, __) =>
|
||||
const _LoadingOverlay(isLoading: true),
|
||||
errorWidget: (_, __, ___) =>
|
||||
_LoadingOverlay(isLoading: false),
|
||||
const _LoadingOverlay(isLoading: false),
|
||||
)
|
||||
else
|
||||
_LoadingOverlay(isLoading: false),
|
||||
const _LoadingOverlay(isLoading: false),
|
||||
if (hasVideo && !isReady)
|
||||
Positioned.fill(
|
||||
const Positioned.fill(
|
||||
child: _LoadingOverlay(isLoading: true),
|
||||
),
|
||||
],
|
||||
@ -590,12 +591,12 @@ class _AspectRatioImageState extends State<_AspectRatioImage> {
|
||||
placeholder: (_, __) => SizedBox(
|
||||
width: widget.maxWidth,
|
||||
height: widget.maxWidth,
|
||||
child: _LoadingOverlay(isLoading: true),
|
||||
child: const _LoadingOverlay(isLoading: true),
|
||||
),
|
||||
errorWidget: (_, __, ___) => SizedBox(
|
||||
width: 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,
|
||||
),
|
||||
)
|
||||
: Icon(
|
||||
: const Icon(
|
||||
LucideIcons.video,
|
||||
size: 48,
|
||||
color: AppColors.textMuted,
|
||||
@ -785,7 +786,7 @@ class _GenerateButton extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
const Icon(
|
||||
LucideIcons.sparkles,
|
||||
size: 16,
|
||||
color: AppColors.surface,
|
||||
|
||||
@ -136,7 +136,7 @@ class _GenerationResultScreenState extends State<GenerationResultScreen> {
|
||||
),
|
||||
),
|
||||
body: widget.mediaItem == null
|
||||
? Center(
|
||||
? const Center(
|
||||
child: Text(
|
||||
'No media',
|
||||
style: TextStyle(color: AppColors.textSecondary),
|
||||
@ -208,7 +208,7 @@ class _MediaDisplay extends StatelessWidget {
|
||||
? Container(
|
||||
color: AppColors.textPrimary,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
'Load failed',
|
||||
style: TextStyle(color: AppColors.surface),
|
||||
),
|
||||
@ -377,7 +377,8 @@ class _DownloadButton extends StatelessWidget {
|
||||
),
|
||||
)
|
||||
else
|
||||
Icon(LucideIcons.download, size: 20, color: AppColors.surface),
|
||||
const Icon(LucideIcons.download,
|
||||
size: 20, color: AppColors.surface),
|
||||
const SizedBox(width: AppSpacing.md),
|
||||
Text(
|
||||
saving ? 'Saving...' : 'Save to Album',
|
||||
@ -407,18 +408,18 @@ class _ShareButton extends StatelessWidget {
|
||||
color: AppColors.surface,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: AppColors.border),
|
||||
boxShadow: [
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: AppColors.shadowLight,
|
||||
blurRadius: 6,
|
||||
offset: const Offset(0, 2),
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
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),
|
||||
Text(
|
||||
'Share',
|
||||
|
||||
@ -144,11 +144,11 @@ class _VideoCardState extends State<VideoCard> {
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: [
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: AppColors.shadowMedium,
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 4),
|
||||
offset: Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -213,7 +213,7 @@ class _VideoCardState extends State<VideoCard> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
const Icon(
|
||||
LucideIcons.sparkles,
|
||||
size: 12,
|
||||
color: AppColors.surface,
|
||||
@ -273,11 +273,11 @@ class _VideoCardState extends State<VideoCard> {
|
||||
color: AppColors.primary,
|
||||
width: 1,
|
||||
),
|
||||
boxShadow: [
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: AppColors.primaryButtonShadow,
|
||||
blurRadius: 6,
|
||||
offset: const Offset(0, 2),
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -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:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../core/api/services/payment_api.dart';
|
||||
import '../../core/log/app_logger.dart';
|
||||
import '../../core/user/account_refresh.dart';
|
||||
import '../../core/user/user_state.dart';
|
||||
@ -232,13 +231,15 @@ abstract final class GooglePlayPurchaseService {
|
||||
|
||||
/// 对单笔购买执行 completePurchase,并在 Android 上显式调用 consumePurchase(autoConsume: false 时必须,否则无法再次购买)。
|
||||
/// 正常流程回调成功后请调用此方法,传入 [GooglePayPurchaseResult.purchaseDetails]。
|
||||
static Future<bool> completeAndConsumePurchase(PurchaseDetails purchaseDetails) async {
|
||||
static Future<bool> completeAndConsumePurchase(
|
||||
PurchaseDetails purchaseDetails) async {
|
||||
final iap = InAppPurchase.instance;
|
||||
try {
|
||||
iap.completePurchase(purchaseDetails);
|
||||
_log.d('completePurchase 已执行');
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
final androidAddition = iap.getPlatformAddition<InAppPurchaseAndroidPlatformAddition>();
|
||||
final androidAddition =
|
||||
iap.getPlatformAddition<InAppPurchaseAndroidPlatformAddition>();
|
||||
final result = await androidAddition.consumePurchase(purchaseDetails);
|
||||
final ok = result.responseCode == BillingResponse.ok;
|
||||
if (ok) {
|
||||
@ -256,7 +257,8 @@ abstract final class GooglePlayPurchaseService {
|
||||
}
|
||||
|
||||
/// 执行 completePurchase + consumePurchase(补单内部用)。
|
||||
static Future<bool> _consumePurchase(InAppPurchase iap, UnacknowledgedGooglePayPurchase p) async {
|
||||
static Future<bool> _consumePurchase(
|
||||
InAppPurchase iap, UnacknowledgedGooglePayPurchase p) async {
|
||||
return completeAndConsumePurchase(p.purchaseDetails);
|
||||
}
|
||||
|
||||
@ -294,7 +296,8 @@ abstract final class GooglePlayPurchaseService {
|
||||
final line = (data?['line']?.toString() ?? '').toUpperCase();
|
||||
final status = (data?['status']?.toString() ?? '').toUpperCase();
|
||||
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 (await _consumePurchase(iap, p)) {
|
||||
_pendingFromStream.remove(p.orderId);
|
||||
|
||||
@ -27,13 +27,13 @@ class BottomNavBar extends StatelessWidget {
|
||||
horizontal: AppSpacing.screenPadding,
|
||||
vertical: 7.5,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.surface,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.shadowSoft,
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, -4),
|
||||
offset: Offset(0, -4),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -38,7 +38,8 @@ class CreditsBadge extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(LucideIcons.sparkles, size: 16, color: AppColors.primary),
|
||||
const Icon(LucideIcons.sparkles,
|
||||
size: 16, color: AppColors.primary),
|
||||
const SizedBox(width: AppSpacing.sm),
|
||||
Text(
|
||||
credits,
|
||||
|
||||
@ -30,13 +30,13 @@ class TopNavBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
return Container(
|
||||
height: 56,
|
||||
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.screenPadding),
|
||||
decoration: BoxDecoration(
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.surface,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.shadowLight,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -46,7 +46,7 @@ class TopNavBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
GestureDetector(
|
||||
onTap: onBack ?? () => Navigator.of(context).pop(),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: SizedBox(
|
||||
child: const SizedBox(
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: Center(
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
name: pets_hero_ai
|
||||
description: PetsHero AI Application.
|
||||
publish_to: 'none'
|
||||
version: 1.0.3+4
|
||||
version: 1.0.4+5
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user