Files
arcx-app/lib/features/iap/presentation/iap_unlock_dialog.dart
2026-08-08 10:57:54 +08:00

157 lines
4.7 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:arcx/app/app_theme.dart';
import 'package:arcx/features/iap/application/iap_controller.dart';
class IapUnlockDialog extends ConsumerWidget {
const IapUnlockDialog({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final iap = ref.watch(iapControllerProvider);
final product = iap.product;
ref.listen(iapControllerProvider, (prev, next) {
if (next.lastEvent != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(next.lastEvent!)),
);
if (next.lastEvent!.contains('解锁') ||
next.lastEvent!.contains('恢复')) {
Navigator.of(context).pop();
}
} else if (next.errorMessage != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(next.errorMessage!)),
);
}
});
return AlertDialog(
title: const Text('解锁记分本'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'免费试用次数已用完。购买后即可永久解锁无限记分权益,无需联网即可使用。',
style: TextStyle(fontSize: 14),
),
const SizedBox(height: 16),
_PriceRow(
title: product?.title ?? '记分本永久解锁',
price: iap.productsAvailable && product != null
? product.price
: '—',
),
const SizedBox(height: 8),
_FeatureItem(text: '无限次记分训练'),
_FeatureItem(text: '本地永久保存训练数据'),
_FeatureItem(text: '一次购买,永久使用'),
if (iap.isLoading) ...[
const SizedBox(height: 12),
const Center(child: CircularProgressIndicator()),
],
],
),
),
actions: [
TextButton(
onPressed: iap.isPurchasing
? null
: () => Navigator.of(context).pop(),
child: const Text('暂不解锁'),
),
TextButton(
onPressed: iap.isPurchasing ? null : () => ref.read(iapControllerProvider.notifier).restore(),
child: const Text('恢复购买'),
),
FilledButton(
onPressed: iap.isPurchasing || iap.isLoading
? null
: () => _unlock(context, ref, iap),
child: iap.isPurchasing
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white),
)
: const Text('立即解锁'),
),
],
);
}
Future<void> _unlock(
BuildContext context,
WidgetRef ref,
IapState iap,
) async {
// In debug builds with no App Store product configured, fall back to a
// dev unlock so the app remains usable for testing.
if (kDebugMode && !iap.productsAvailable) {
await ref.read(iapControllerProvider.notifier).debugUnlock();
if (context.mounted) Navigator.of(context).pop();
return;
}
await ref.read(iapControllerProvider.notifier).buy();
}
}
class _PriceRow extends StatelessWidget {
const _PriceRow({required this.title, required this.price});
final String title;
final String price;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: AppTheme.surfaceMuted,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(
child: Text(
title,
style: const TextStyle(fontWeight: FontWeight.w600),
),
),
Text(
price,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
color: AppTheme.primary,
),
),
],
),
);
}
}
class _FeatureItem extends StatelessWidget {
const _FeatureItem({required this.text});
final String text;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 8),
child: Row(
children: [
const Icon(Icons.check_circle, color: AppTheme.primary, size: 18),
const SizedBox(width: 8),
Text(text, style: const TextStyle(fontSize: 13)),
],
),
);
}
}