mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2025-04-20 16:30:41 +00:00
close AnimatedDialog
through context
This commit is contained in:
parent
2a4d79e35a
commit
8fdbc102b6
4 changed files with 156 additions and 50 deletions
|
@ -18,11 +18,8 @@ class _LightmeterProAnimatedDialogState extends State<LightmeterProAnimatedDialo
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return AnimatedDialog(
|
||||||
onTap: () {
|
closedChild: ReadingValueContainer(
|
||||||
IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures);
|
|
||||||
},
|
|
||||||
child: ReadingValueContainer(
|
|
||||||
color: Theme.of(context).colorScheme.errorContainer,
|
color: Theme.of(context).colorScheme.errorContainer,
|
||||||
values: [
|
values: [
|
||||||
ReadingValue(
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@ class AnimatedDialog extends StatefulWidget {
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static Future<void>? maybeClose(BuildContext context) =>
|
||||||
|
context.findAncestorWidgetOfExactType<_AnimatedOverlay>()?.onDismiss();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AnimatedDialog> createState() => AnimatedDialogState();
|
State<AnimatedDialog> createState() => AnimatedDialogState();
|
||||||
}
|
}
|
||||||
|
@ -147,9 +150,9 @@ class AnimatedDialogState extends State<AnimatedDialog> with SingleTickerProvide
|
||||||
_sizeTween = SizeTween(
|
_sizeTween = SizeTween(
|
||||||
begin: _closedSize,
|
begin: _closedSize,
|
||||||
end: Size(
|
end: Size(
|
||||||
min(widget.openedSize?.width ?? double.maxFinite, maxWidth),
|
min(widget.openedSize?.width ?? double.maxFinite, maxWidth),
|
||||||
min(widget.openedSize?.height ?? double.maxFinite, maxHeight),
|
min(widget.openedSize?.height ?? double.maxFinite, maxHeight),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
_sizeAnimation = _sizeTween.animate(_defaultCurvedAnimation);
|
_sizeAnimation = _sizeTween.animate(_defaultCurvedAnimation);
|
||||||
|
|
||||||
|
@ -230,7 +233,7 @@ class _AnimatedOverlay extends StatelessWidget {
|
||||||
final Animation<double> borderRadiusAnimation;
|
final Animation<double> borderRadiusAnimation;
|
||||||
final Animation<Color?> foregroundColorAnimation;
|
final Animation<Color?> foregroundColorAnimation;
|
||||||
final Animation<double> elevationAnimation;
|
final Animation<double> elevationAnimation;
|
||||||
final VoidCallback onDismiss;
|
final Future<void> Function() onDismiss;
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
final Widget Function(BuildContext context)? builder;
|
final Widget Function(BuildContext context)? builder;
|
||||||
|
|
||||||
|
|
|
@ -1,59 +1,53 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/data/models/feature.dart';
|
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/providers/remote_config_provider.dart';
|
|
||||||
import 'package:lightmeter/res/dimens.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';
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||||
|
|
||||||
Future<void> showBuyProDialog(BuildContext context) {
|
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(
|
return showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => AlertDialog(
|
builder: (_) => Dialog(
|
||||||
icon: const Icon(Icons.star),
|
child: const ProFeaturesDialog(),
|
||||||
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,
|
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: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: Navigator.of(context).pop,
|
onPressed: () => _close(context),
|
||||||
child: Text(S.of(context).cancel),
|
child: Text(S.of(context).cancel),
|
||||||
),
|
),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
_close(context).then((_) => IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures));
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue