close AnimatedDialog through context

This commit is contained in:
Vadim 2024-01-12 12:55:29 +01:00
parent 2a4d79e35a
commit 8fdbc102b6
4 changed files with 156 additions and 50 deletions

View file

@ -18,11 +18,8 @@ class _LightmeterProAnimatedDialogState extends State<LightmeterProAnimatedDialo
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures);
},
child: ReadingValueContainer(
return AnimatedDialog(
closedChild: ReadingValueContainer(
color: Theme.of(context).colorScheme.errorContainer,
values: [
ReadingValue(
@ -31,6 +28,44 @@ class _LightmeterProAnimatedDialogState extends State<LightmeterProAnimatedDialo
),
],
),
openedChild: ProFeaturesDialog(),
openedSize: Size.fromHeight(height(context)),
);
}
double height(BuildContext context) {
double textHeight(
BuildContext context,
String text,
TextStyle? style,
double horizontalPadding,
) {
final TextPainter titlePainter = TextPainter(
text: TextSpan(
text: text,
style: style,
),
textDirection: TextDirection.ltr,
)..layout(maxWidth: MediaQuery.of(context).size.width - Dimens.dialogMargin.horizontal - horizontalPadding);
return titlePainter.size.height;
}
final titleHeight = textHeight(
context,
S.of(context).unlockProFeatures,
Theme.of(context).textTheme.headlineSmall,
Dimens.dialogIconTitlePadding.horizontal,
);
final contentHeight = textHeight(
context,
S.of(context).unlockProFeaturesDescription,
Theme.of(context).textTheme.bodyMedium,
Dimens.paddingL * 2,
);
return (IconTheme.of(context).size! + Dimens.dialogTitlePadding.vertical) + // icon + icon padding
(titleHeight + Dimens.dialogIconTitlePadding.vertical) + // title + title padding
contentHeight +
(48 + Dimens.dialogActionsPadding.vertical); // actions + actions padding
}
}

View file

@ -21,6 +21,9 @@ class AnimatedDialog extends StatefulWidget {
super.key,
});
static Future<void>? maybeClose(BuildContext context) =>
context.findAncestorWidgetOfExactType<_AnimatedOverlay>()?.onDismiss();
@override
State<AnimatedDialog> createState() => AnimatedDialogState();
}
@ -147,9 +150,9 @@ class AnimatedDialogState extends State<AnimatedDialog> with SingleTickerProvide
_sizeTween = SizeTween(
begin: _closedSize,
end: Size(
min(widget.openedSize?.width ?? double.maxFinite, maxWidth),
min(widget.openedSize?.height ?? double.maxFinite, maxHeight),
),
min(widget.openedSize?.width ?? double.maxFinite, maxWidth),
min(widget.openedSize?.height ?? double.maxFinite, maxHeight),
),
);
_sizeAnimation = _sizeTween.animate(_defaultCurvedAnimation);
@ -230,7 +233,7 @@ class _AnimatedOverlay extends StatelessWidget {
final Animation<double> borderRadiusAnimation;
final Animation<Color?> foregroundColorAnimation;
final Animation<double> elevationAnimation;
final VoidCallback onDismiss;
final Future<void> Function() onDismiss;
final Widget? child;
final Widget Function(BuildContext context)? builder;

View file

@ -1,59 +1,53 @@
import 'package:flutter/material.dart';
import 'package:lightmeter/data/models/feature.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/providers/remote_config_provider.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart';
import 'package:lightmeter/screens/shared/transparent_dialog/widget_dialog_transparent.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
Future<void> showBuyProDialog(BuildContext context) {
final unlockFeaturesEnabled = RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText);
Widget splitDescription() {
final description =
unlockFeaturesEnabled ? S.of(context).unlockProFeaturesDescription : S.of(context).lightmeterProDescription;
final paragraphs = description.split('\n\n');
final features = paragraphs.first.split('\n \u2022 ').sublist(1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(paragraphs.first.split('\n \u2022 ').first),
...features.map(
(f) => Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('\u2022 '),
Flexible(child: Text(f)),
],
),
),
Text('\n${paragraphs.last}'),
],
);
}
return showDialog(
context: context,
builder: (_) => AlertDialog(
icon: const Icon(Icons.star),
titlePadding: Dimens.dialogIconTitlePadding,
title: Text(unlockFeaturesEnabled ? S.of(context).proFeatures : S.of(context).lightmeterPro),
contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
content: SingleChildScrollView(child: splitDescription()),
actionsPadding: Dimens.dialogActionsPadding,
builder: (_) => Dialog(
child: const ProFeaturesDialog(),
),
);
}
class ProFeaturesDialog extends StatelessWidget {
const ProFeaturesDialog({super.key});
@override
Widget build(BuildContext context) {
return TransparentDialog(
icon: Icons.star,
title: S.of(context).proFeatures,
scrollableContent: false,
content: Flexible(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
child: Text(
S.of(context).unlockProFeaturesDescription,
style: Theme.of(context).textTheme.bodyMedium,
),
),
),
),
actions: [
TextButton(
onPressed: Navigator.of(context).pop,
onPressed: () => _close(context),
child: Text(S.of(context).cancel),
),
FilledButton(
onPressed: () {
Navigator.of(context).pop();
IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures);
_close(context).then((_) => IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures));
},
child: Text(unlockFeaturesEnabled ? S.of(context).unlock : S.of(context).buy),
child: Text(S.of(context).unlock),
),
],
),
);
);
}
Future<void> _close(BuildContext context) async => AnimatedDialog.maybeClose(context) ?? Navigator.of(context).pop();
}

View file

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:lightmeter/res/dimens.dart';
class TransparentDialog extends StatelessWidget {
final IconData icon;
final String title;
final String? subtitle;
final Widget content;
final bool scrollableContent;
final List<Widget> actions;
const TransparentDialog({
required this.icon,
required this.title,
this.subtitle,
required this.content,
required this.scrollableContent,
this.actions = const [],
super.key,
});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: Dimens.dialogTitlePadding,
child: Icon(icon),
),
Padding(
padding: Dimens.dialogIconTitlePadding,
child: Text(
title,
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
),
if (subtitle != null)
Padding(
padding: Dimens.dialogIconTitlePadding,
child: Text(
subtitle!,
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
),
],
),
if (scrollableContent) const Divider(),
content,
if (scrollableContent) const Divider(),
Padding(
padding: Dimens.dialogActionsPadding,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: _actions().toList(),
),
),
],
);
}
Iterable<Widget> _actions() sync* {
for (int i = 0; i < actions.length; i++) {
yield i == 0 ? const Spacer() : const SizedBox(width: Dimens.grid16);
yield actions[i];
}
}
}