// ignore_for_file: use_build_context_synchronously
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:logger/logger.dart';
import 'package:music_train_lottery/models/wallet_model.dart';
import 'package:music_train_lottery/theme/theme_helper.dart';
import 'package:music_train_lottery/utils/constants.dart';
import '../popups/currency_popup.dart';
import '../theme/custom_button_style.dart';
import '../theme/custom_text_style.dart';
import '../utils/IAP.dart';
import '../utils/custom_widgets_builder.dart';
import '../utils/image_constant.dart';
import '../utils/shared_preferences.dart';
class WalletPage extends StatefulWidget {
const WalletPage({super.key});
@override
State<WalletPage> createState() => _WalletPageState();
}
class _WalletPageState extends State<WalletPage> {
final IAPService _iapService = IAPService();
final Logger _logger = Logger();
late StreamSubscription<List<PurchaseDetails>> _subscription;
// Toggle this to true to use dummy data instead of real IAP fetch
final bool _useDummyData = true;
List<ProductDetails> _products = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
_subscription = InAppPurchase.instance.purchaseStream.listen(
_onPurchaseUpdated,
onDone: () => _subscription.cancel(),
);
_loadProducts();
}
// @override
// void initState() {
// super.initState();
// _subscription = InAppPurchase.instance.purchaseStream.listen((purchases) {
// _iapService.onPurchaseUpdated(purchases);
// }, onDone: () {
// _subscription.cancel();
// });
// _initStoreInfo();
// }
Future<void> _loadProducts() async {
setState(() => _isLoading = true);
if (_useDummyData) {
// Provide dummy list for testing
await Future.delayed(const Duration(seconds: 1)); // simulate network delay
setState(() {
_products = [
ProductDetails(
id: 'dummy_100_coins',
title: '100 Coins Pack',
description: 'Get 100 coins to use in the app',
price: '\$0.99',
rawPrice: 0.99,
currencyCode: 'USD',
),
ProductDetails(
id: 'dummy_500_coins',
title: '500 Coins Pack',
description: 'Best value: 500 coins',
price: '\$3.99',
rawPrice: 3.99,
currencyCode: 'USD',
),
ProductDetails(
id: 'dummy_1000_coins',
title: '1000 Coins Pack',
description: 'Ultimate pack: 1000 coins',
price: '\$6.99',
rawPrice: 6.99,
currencyCode: 'USD',
),
];
_isLoading = false;
});
} else {
try {
await _iapService.init();
final products = await _iapService.fetchProducts(_iapService.productIds);
setState(() {
_products = products;
_isLoading = false;
});
} catch (e) {
_logger.e('Failed to load products: $e');
setState(() => _isLoading = false);
}
}
}
void _onPurchaseUpdated(List<PurchaseDetails> purchases) async {
for (var p in purchases) {
if (p.status == PurchaseStatus.purchased) {
// Verify then deliver
await _verifyAndDeliver(p);
} else if (p.status == PurchaseStatus.error) {
_logger.e('Purchase error: ${p.error}');
}
if (p.pendingCompletePurchase) {
await InAppPurchase.instance.completePurchase(p);
}
}
}
Future<void> _verifyAndDeliver(PurchaseDetails purchase) async {
// Here you would verify with your server if needed
double amount = purchase.productID.contains('1000')
? 6.99
: purchase.productID.contains('500')
? 3.99
: 0.99;
final walletRef = FirebaseFirestore.instance
.collection('users')
.doc("")
.collection('userData')
.doc('walletData');
final snapshot = await walletRef.get();
final data = snapshot.data() ?? {};
double currentBalance = double.tryParse(data['available_balance'] ?? '0') ?? 0;
List history = List.from(data['historyData'] ?? []);
double updatedBalance = currentBalance + amount;
history.add({
'balance': '+\$${amount.toStringAsFixed(2)}',
'currency': '\$',
'name': 'IAP Top-up',
'timestamp': FieldValue.serverTimestamp(),
});
await walletRef.update({
'available_balance': updatedBalance.toStringAsFixed(2),
'historyData': history,
});
_logger.i('Wallet updated: \$${updatedBalance.toStringAsFixed(2)}');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Purchase successful! Wallet topped up.')),
);
}
@override
void dispose() {
_subscription.cancel();
_iapService.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
initialData: null,
future: rootBundle.loadString('assets/Common-Currency.json'),
builder: (context, currency) {
return SafeArea(
child: AnnotatedRegion(
value: const SystemUiOverlayStyle(
statusBarColor: kWhiteColor,
statusBarIconBrightness: Brightness.dark,
),
child: Scaffold(
body: FutureBuilder(
initialData: null,
future: Prefs.getString('userID'),
builder: (context, user) {
return StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance
.collection('users')
.doc(user.data)
.collection('userData')
.doc('walletData')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(
color: kLightAccentColor,
),
);
}
WalletData walletData =
WalletData.fromFirestore(snapshot.data!);
final balance = walletData.availableBalance.split('.');
return SingleChildScrollView(
child: Container(
width: double.maxFinite,
padding: REdgeInsets.symmetric(
horizontal: 15.w,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () => Navigator.pop(context),
child: Container(
padding: REdgeInsets.symmetric(
horizontal: 12.0,
vertical: 10.0,
),
decoration: BoxDecoration(
border: Border.all(
color: kLightAccentColor,
width: 1.0,
),
borderRadius:
BorderRadius.circular(10.0),
),
child: SvgPicture.asset(
ImageConstant.imgArrowLeftGreenA700,
height: 15.h,
width: 15.w,
),
),
),
Text(
"Wallet",
style: theme.textTheme.bodyLarge!
.copyWith(
color: kLightTextColor,
fontWeight: FontWeight.bold),
),
SvgPicture.asset(
ImageConstant.imgUser,
height: 46.h,
width: 40.w,
),
],
),
kPageItemSpacing2,
InkWell(
onTap: () {
_showPurchaseDialog();
// _showCurrencyPopup(
// context, currency.data!, user.data!);
},
child: Container(
width: double.maxFinite,
height: 200.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.r),
color: kLightPrimaryColor,
),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Text(
"Main Balance",
style: CustomTextStyles
.bodySmallWhiteA700,
),
kPageItemSpacing,
RichText(
text: TextSpan(children: [
TextSpan(
text: '\$${balance.first}',
style: theme
.textTheme.displaySmall,
),
TextSpan(
text: ".${balance.last}",
style: CustomTextStyles
.bodyLargeSoraffffffff,
)
]),
textAlign: TextAlign.left),
kPageItemSpacing1,
SvgPicture.asset(
ImageConstant.imgUploadLine,
height: 16.h,
width: 16.w,
),
kPageItemSpacing1,
Text(
"Top up",
style: CustomTextStyles
.bodySmallWhiteA700,
),
],
),
),
),
kPageItemSpacing2,
Text(
"History",
style:
theme.textTheme.headlineSmall!.copyWith(
color: kLightPrimaryColor,
),
),
kPageItemSpacing1,
ListView.separated(
shrinkWrap: true,
reverse: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: walletData.history.length,
itemBuilder:
(BuildContext context, int index) {
return CustomWidgetsBuilder
.buildHistoryItemRow(
walletData.history[index],
context,
walletData.history[index]['balance'],
ImageConstant.imgPlay,
"Bought",
CustomButtonStyles.fillGreenA,
);
},
separatorBuilder:
(BuildContext context, int index) {
return CustomWidgetsBuilder
.buildLotteryItemRowDivider(
context,
appTheme.blueGray50,
0,
4.0,
0,
);
},
),
],
),
),
);
},
);
},
),
),
),
);
});
}
void _showCurrencyPopup(
BuildContext context, String jsonData, String userId) async {
showDialog(
context: context,
builder: (BuildContext context) {
return CurrencyPopup(
jsonData: jsonData,
userId: userId,
);
},
);
}
void _showPurchaseDialog() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Available Products'),
content: SizedBox(
width: double.maxFinite,
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _products.isEmpty
? const Text('No products available')
: ListView.builder(
shrinkWrap: true,
itemCount: _products.length,
itemBuilder: (context, index) {
final product = _products[index];
return ListTile(
title: Text(product.title),
subtitle: Text(product.description),
trailing: TextButton(
child: Text(product.price),
onPressed: () {
Navigator.of(context).pop();
_iapService.buy(product);
},
),
);
},
),
),
actions: [
TextButton(
child: const Text('Close'),
onPressed: () => Navigator.of(context).pop(),
),
],
);
},
);
}
}