mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2025-08-26 15:06:43 +00:00
don't fetch products
This commit is contained in:
parent
e24bd8b2ec
commit
b83f3193c3
2 changed files with 109 additions and 89 deletions
|
@ -1,7 +1,4 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/res/theme.dart';
|
||||
|
@ -9,7 +6,12 @@ import 'package:lightmeter/screens/shared/button/widget_button_filled_large.dart
|
|||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
||||
class LightmeterProOffering extends StatefulWidget {
|
||||
const LightmeterProOffering({super.key});
|
||||
const LightmeterProOffering({
|
||||
super.key,
|
||||
required this.onBuyProduct,
|
||||
});
|
||||
|
||||
final ValueChanged<IAPProduct> onBuyProduct;
|
||||
|
||||
@override
|
||||
State<LightmeterProOffering> createState() => _LightmeterProOfferingState();
|
||||
|
@ -17,29 +19,12 @@ class LightmeterProOffering extends StatefulWidget {
|
|||
|
||||
class _LightmeterProOfferingState extends State<LightmeterProOffering> {
|
||||
late final Future<List<IAPProduct>> productsFuture;
|
||||
bool _isLoading = true;
|
||||
IAPProduct? monthly;
|
||||
IAPProduct? yearly;
|
||||
IAPProduct? lifetime;
|
||||
IAPProduct? selected;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
productsFuture = IAPProductsProvider.of(context).fetchProducts();
|
||||
productsFuture.then((products) async {
|
||||
monthly = products.firstWhereOrNull((p) => p.type == PurchaseType.monthly);
|
||||
yearly = products.firstWhereOrNull((p) => p.type == PurchaseType.yearly);
|
||||
lifetime = products.firstWhereOrNull((p) => p.type == PurchaseType.lifetime);
|
||||
selected = monthly ?? lifetime;
|
||||
}).onError((e, __) {
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
_showSnackbar(e.toString());
|
||||
});
|
||||
}).whenComplete(() {
|
||||
_isLoading = false;
|
||||
if (mounted) setState(() {});
|
||||
});
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
selected = IAPProducts.of(context).monthly ?? IAPProducts.of(context).lifetime;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -66,78 +51,29 @@ class _LightmeterProOfferingState extends State<LightmeterProOffering> {
|
|||
if (!_isLifetimeOnly)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: Dimens.paddingS),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
AnimatedOpacity(
|
||||
duration: Dimens.durationM,
|
||||
opacity: _isLoading ? Dimens.disabledOpacity : Dimens.enabledOpacity,
|
||||
child: _Products(
|
||||
monthly: monthly,
|
||||
yearly: yearly,
|
||||
lifetime: lifetime,
|
||||
selected: selected,
|
||||
onProductSelected: _selectProduct,
|
||||
),
|
||||
),
|
||||
if (_isLoading)
|
||||
const SizedBox(
|
||||
height: 120,
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
],
|
||||
child: _Products(
|
||||
monthly: IAPProducts.of(context).monthly,
|
||||
yearly: IAPProducts.of(context).yearly,
|
||||
lifetime: IAPProducts.of(context).lifetime,
|
||||
selected: selected,
|
||||
onProductSelected: _selectProduct,
|
||||
),
|
||||
),
|
||||
FilledButtonLarge(
|
||||
title: S.of(context).continuePurchase,
|
||||
onPressed: _isLoading || selected != null ? _buyPro : null,
|
||||
onPressed: selected != null ? () => widget.onBuyProduct(selected!) : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool get _isLifetimeOnly => lifetime != null && yearly == null && monthly == null;
|
||||
bool get _isLifetimeOnly => !IAPProducts.of(context).hasSubscriptions;
|
||||
|
||||
void _selectProduct(IAPProduct product) {
|
||||
if (!_isLoading) {
|
||||
setState(() {
|
||||
selected = product;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _buyPro() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
selected = product;
|
||||
});
|
||||
try {
|
||||
final isPro = await IAPProductsProvider.of(context).buyPro(selected!);
|
||||
if (mounted && isPro) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
} on PlatformException catch (e) {
|
||||
_showSnackbar(e.message ?? '');
|
||||
} catch (e) {
|
||||
_showSnackbar(e.toString());
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _showSnackbar(String message) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lightmeter/data/models/app_feature.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
|
@ -8,21 +9,30 @@ import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
|
|||
import 'package:lightmeter/utils/text_height.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
||||
class LightmeterProScreen extends StatelessWidget {
|
||||
class LightmeterProScreen extends StatefulWidget {
|
||||
const LightmeterProScreen({super.key});
|
||||
|
||||
@override
|
||||
State<LightmeterProScreen> createState() => _LightmeterProScreenState();
|
||||
}
|
||||
|
||||
class _LightmeterProScreenState extends State<LightmeterProScreen> {
|
||||
final features =
|
||||
defaultTargetPlatform == TargetPlatform.android ? AppFeature.androidFeatures : AppFeature.iosFeatures;
|
||||
|
||||
LightmeterProScreen({super.key});
|
||||
final _isRestoringPurchases = ValueNotifier(false);
|
||||
final _isPurchasingProduct = ValueNotifier(false);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SliverScreen(
|
||||
title: Text(S.of(context).proFeaturesTitle),
|
||||
appBarActions: [
|
||||
IconButton(
|
||||
onPressed: IAPProductsProvider.of(context).restorePurchases,
|
||||
icon: const Icon(Icons.restore),
|
||||
tooltip: S.of(context).restorePurchases,
|
||||
/// Restoration is working, but it does not trigger pop
|
||||
/// add await of didChangeDependencies
|
||||
_RestorePurchasesButton(
|
||||
valueListenable: _isRestoringPurchases,
|
||||
onPressed: _restorePurchases,
|
||||
),
|
||||
],
|
||||
slivers: [
|
||||
|
@ -65,7 +75,81 @@ class LightmeterProScreen extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
],
|
||||
bottomNavigationBar: const LightmeterProOffering(),
|
||||
bottomNavigationBar: LightmeterProOffering(onBuyProduct: _buyPro),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _restorePurchases() async {
|
||||
_isRestoringPurchases.value = true;
|
||||
try {
|
||||
final isPro = await IAPProductsProvider.of(context).restorePurchases();
|
||||
if (mounted && isPro) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
} on PlatformException catch (e) {
|
||||
_showSnackbar(e.message ?? '');
|
||||
} catch (e) {
|
||||
_showSnackbar(e.toString());
|
||||
} finally {
|
||||
_isRestoringPurchases.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _buyPro(IAPProduct product) async {
|
||||
_isPurchasingProduct.value = true;
|
||||
try {
|
||||
final isPro = await IAPProductsProvider.of(context).buyPro(product);
|
||||
if (mounted && isPro) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
} on PlatformException catch (e) {
|
||||
_showSnackbar(e.message ?? '');
|
||||
} catch (e) {
|
||||
_showSnackbar(e.toString());
|
||||
} finally {
|
||||
_isPurchasingProduct.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
void _showSnackbar(String message) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _RestorePurchasesButton extends StatelessWidget {
|
||||
const _RestorePurchasesButton({
|
||||
required this.valueListenable,
|
||||
required this.onPressed,
|
||||
});
|
||||
|
||||
final ValueNotifier<bool> valueListenable;
|
||||
final VoidCallback onPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: valueListenable,
|
||||
builder: (context, value, _) {
|
||||
if (value) {
|
||||
return const SizedBox.square(
|
||||
dimension: Dimens.grid24 - Dimens.grid4,
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
} else {
|
||||
return IconButton(
|
||||
onPressed: onPressed,
|
||||
icon: const Icon(Icons.restore),
|
||||
tooltip: S.of(context).restorePurchases,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue