打包:版本发布
This commit is contained in:
parent
066d8b7391
commit
596fe05e09
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -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 上显式调用 consumePurchase(autoConsume: false 时必须,否则无法再次购买)。
|
/// 对单笔购买执行 completePurchase,并在 Android 上显式调用 consumePurchase(autoConsume: 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);
|
||||||
|
|||||||
@ -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),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user