blob: faae485f3028ae5533ee261e7f7411b680098d51 [file] [log] [blame]
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/gallery_localizations.dart';
// BEGIN openContainerTransformDemo
const String _loremIpsumParagraph =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod '
'tempor incididunt ut labore et dolore magna aliqua. Vulputate dignissim '
'suspendisse in est. Ut ornare lectus sit amet. Eget nunc lobortis mattis '
'aliquam faucibus purus in. Hendrerit gravida rutrum quisque non tellus '
'orci ac auctor. Mattis aliquam faucibus purus in massa. Tellus rutrum '
'tellus pellentesque eu tincidunt tortor. Nunc eget lorem dolor sed. Nulla '
'at volutpat diam ut venenatis tellus in metus. Tellus cras adipiscing enim '
'eu turpis. Pretium fusce id velit ut tortor. Adipiscing enim eu turpis '
'egestas pretium. Quis varius quam quisque id. Blandit aliquam etiam erat '
'velit scelerisque. In nisl nisi scelerisque eu. Semper risus in hendrerit '
'gravida rutrum quisque. Suspendisse in est ante in nibh mauris cursus '
'mattis molestie. Adipiscing elit duis tristique sollicitudin nibh sit '
'amet commodo nulla. Pretium viverra suspendisse potenti nullam ac tortor '
'vitae.\n'
'\n'
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod '
'tempor incididunt ut labore et dolore magna aliqua. Vulputate dignissim '
'suspendisse in est. Ut ornare lectus sit amet. Eget nunc lobortis mattis '
'aliquam faucibus purus in. Hendrerit gravida rutrum quisque non tellus '
'orci ac auctor. Mattis aliquam faucibus purus in massa. Tellus rutrum '
'tellus pellentesque eu tincidunt tortor. Nunc eget lorem dolor sed. Nulla '
'at volutpat diam ut venenatis tellus in metus. Tellus cras adipiscing enim '
'eu turpis. Pretium fusce id velit ut tortor. Adipiscing enim eu turpis '
'egestas pretium. Quis varius quam quisque id. Blandit aliquam etiam erat '
'velit scelerisque. In nisl nisi scelerisque eu. Semper risus in hendrerit '
'gravida rutrum quisque. Suspendisse in est ante in nibh mauris cursus '
'mattis molestie. Adipiscing elit duis tristique sollicitudin nibh sit '
'amet commodo nulla. Pretium viverra suspendisse potenti nullam ac tortor '
'vitae';
const double _fabDimension = 56;
class OpenContainerTransformDemo extends StatefulWidget {
const OpenContainerTransformDemo({super.key});
@override
State<OpenContainerTransformDemo> createState() =>
_OpenContainerTransformDemoState();
}
class _OpenContainerTransformDemoState
extends State<OpenContainerTransformDemo> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
ContainerTransitionType _transitionType = ContainerTransitionType.fade;
void _showSettingsBottomModalSheet(BuildContext context) {
final localizations = GalleryLocalizations.of(context);
showModalBottomSheet<void>(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setModalState) {
return Container(
height: 125,
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
localizations!.demoContainerTransformModalBottomSheetTitle,
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(
height: 12,
),
ToggleButtons(
borderRadius: BorderRadius.circular(2),
selectedBorderColor: Theme.of(context).colorScheme.primary,
onPressed: (index) {
setModalState(() {
setState(() {
_transitionType = index == 0
? ContainerTransitionType.fade
: ContainerTransitionType.fadeThrough;
});
});
},
isSelected: <bool>[
_transitionType == ContainerTransitionType.fade,
_transitionType == ContainerTransitionType.fadeThrough,
],
children: [
Text(
localizations.demoContainerTransformTypeFade,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Text(
localizations.demoContainerTransformTypeFadeThrough,
),
),
],
),
],
),
);
},
);
},
);
}
@override
Widget build(BuildContext context) {
final localizations = GalleryLocalizations.of(context);
final colorScheme = Theme.of(context).colorScheme;
return Navigator(
// Adding [ValueKey] to make sure that the widget gets rebuilt when
// changing type.
key: ValueKey(_transitionType),
onGenerateRoute: (settings) {
return MaterialPageRoute<void>(
builder: (context) => Scaffold(
key: _scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: false,
title: Column(
children: [
Text(
localizations!.demoContainerTransformTitle,
),
Text(
'(${localizations.demoContainerTransformDemoInstructions})',
style: Theme.of(context)
.textTheme
.titleSmall!
.copyWith(color: Colors.white),
),
],
),
actions: [
IconButton(
icon: const Icon(
Icons.settings,
),
onPressed: () {
_showSettingsBottomModalSheet(context);
},
),
],
),
body: ListView(
padding: const EdgeInsets.all(8),
children: [
_OpenContainerWrapper(
transitionType: _transitionType,
closedBuilder: (context, openContainer) {
return _DetailsCard(openContainer: openContainer);
},
),
const SizedBox(height: 16),
_OpenContainerWrapper(
transitionType: _transitionType,
closedBuilder: (context, openContainer) {
return _DetailsListTile(openContainer: openContainer);
},
),
const SizedBox(
height: 16,
),
Row(
children: [
Expanded(
child: _OpenContainerWrapper(
transitionType: _transitionType,
closedBuilder: (context, openContainer) {
return _SmallDetailsCard(
openContainer: openContainer,
subtitle:
localizations.demoMotionPlaceholderSubtitle,
);
},
),
),
const SizedBox(
width: 8,
),
Expanded(
child: _OpenContainerWrapper(
transitionType: _transitionType,
closedBuilder: (context, openContainer) {
return _SmallDetailsCard(
openContainer: openContainer,
subtitle:
localizations.demoMotionPlaceholderSubtitle,
);
},
),
),
],
),
const SizedBox(
height: 16,
),
Row(
children: [
Expanded(
child: _OpenContainerWrapper(
transitionType: _transitionType,
closedBuilder: (context, openContainer) {
return _SmallDetailsCard(
openContainer: openContainer,
subtitle: localizations
.demoMotionSmallPlaceholderSubtitle,
);
},
),
),
const SizedBox(
width: 8,
),
Expanded(
child: _OpenContainerWrapper(
transitionType: _transitionType,
closedBuilder: (context, openContainer) {
return _SmallDetailsCard(
openContainer: openContainer,
subtitle: localizations
.demoMotionSmallPlaceholderSubtitle,
);
},
),
),
const SizedBox(
width: 8,
),
Expanded(
child: _OpenContainerWrapper(
transitionType: _transitionType,
closedBuilder: (context, openContainer) {
return _SmallDetailsCard(
openContainer: openContainer,
subtitle: localizations
.demoMotionSmallPlaceholderSubtitle,
);
},
),
),
],
),
const SizedBox(
height: 16,
),
...List.generate(10, (index) {
return OpenContainer<bool>(
transitionType: _transitionType,
openBuilder: (context, openContainer) =>
const _DetailsPage(),
tappable: false,
closedShape: const RoundedRectangleBorder(),
closedElevation: 0,
closedBuilder: (context, openContainer) {
return ListTile(
leading: Image.asset(
'placeholders/avatar_logo.png',
package: 'flutter_gallery_assets',
width: 40,
),
onTap: openContainer,
title: Text(
'${localizations.demoMotionListTileTitle} ${index + 1}',
),
subtitle: Text(
localizations.demoMotionPlaceholderSubtitle,
),
);
},
);
}),
],
),
floatingActionButton: OpenContainer(
transitionType: _transitionType,
openBuilder: (context, openContainer) => const _DetailsPage(),
closedElevation: 6,
closedShape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(_fabDimension / 2),
),
),
closedColor: colorScheme.secondary,
closedBuilder: (context, openContainer) {
return SizedBox(
height: _fabDimension,
width: _fabDimension,
child: Center(
child: Icon(
Icons.add,
color: colorScheme.onSecondary,
),
),
);
},
),
),
);
},
);
}
}
class _OpenContainerWrapper extends StatelessWidget {
const _OpenContainerWrapper({
required this.closedBuilder,
required this.transitionType,
});
final CloseContainerBuilder closedBuilder;
final ContainerTransitionType transitionType;
@override
Widget build(BuildContext context) {
return OpenContainer<bool>(
transitionType: transitionType,
openBuilder: (context, openContainer) => const _DetailsPage(),
tappable: false,
closedBuilder: closedBuilder,
);
}
}
class _DetailsCard extends StatelessWidget {
const _DetailsCard({required this.openContainer});
final VoidCallback openContainer;
@override
Widget build(BuildContext context) {
final localizations = GalleryLocalizations.of(context)!;
return _InkWellOverlay(
openContainer: openContainer,
height: 300,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
color: Colors.black38,
child: Center(
child: Image.asset(
'placeholders/placeholder_image.png',
package: 'flutter_gallery_assets',
width: 100,
),
),
),
),
ListTile(
title: Text(
localizations.demoMotionPlaceholderTitle,
),
subtitle: Text(
localizations.demoMotionPlaceholderSubtitle,
),
),
Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
bottom: 16,
),
child: Text(
'Lorem ipsum dolor sit amet, consectetur '
'adipiscing elit, sed do eiusmod tempor.',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Colors.black54,
inherit: false,
),
),
),
],
),
);
}
}
class _SmallDetailsCard extends StatelessWidget {
const _SmallDetailsCard({
required this.openContainer,
required this.subtitle,
});
final VoidCallback openContainer;
final String subtitle;
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return _InkWellOverlay(
openContainer: openContainer,
height: 225,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Colors.black38,
height: 150,
child: Center(
child: Image.asset(
'placeholders/placeholder_image.png',
package: 'flutter_gallery_assets',
width: 80,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
GalleryLocalizations.of(context)!
.demoMotionPlaceholderTitle,
style: textTheme.titleLarge,
),
const SizedBox(
height: 4,
),
Text(
subtitle,
style: textTheme.bodySmall,
),
],
),
),
),
],
),
);
}
}
class _DetailsListTile extends StatelessWidget {
const _DetailsListTile({required this.openContainer});
final VoidCallback openContainer;
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
const height = 120.0;
return _InkWellOverlay(
openContainer: openContainer,
height: height,
child: Row(
children: [
Container(
color: Colors.black38,
height: height,
width: height,
child: Center(
child: Image.asset(
'placeholders/placeholder_image.png',
package: 'flutter_gallery_assets',
width: 60,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
GalleryLocalizations.of(context)!
.demoMotionPlaceholderTitle,
style: textTheme.titleMedium,
),
const SizedBox(
height: 8,
),
Text(
'Lorem ipsum dolor sit amet, consectetur '
'adipiscing elit,',
style: textTheme.bodySmall,
),
],
),
),
),
],
),
);
}
}
class _InkWellOverlay extends StatelessWidget {
const _InkWellOverlay({
required this.openContainer,
required this.height,
required this.child,
});
final VoidCallback openContainer;
final double height;
final Widget child;
@override
Widget build(BuildContext context) {
return SizedBox(
height: height,
child: InkWell(
onTap: openContainer,
child: child,
),
);
}
}
class _DetailsPage extends StatelessWidget {
const _DetailsPage();
@override
Widget build(BuildContext context) {
final localizations = GalleryLocalizations.of(context)!;
final textTheme = Theme.of(context).textTheme;
return Scaffold(
appBar: AppBar(
title: Text(
localizations.demoMotionDetailsPageTitle,
),
),
body: ListView(
children: [
Container(
color: Colors.black38,
height: 250,
child: Padding(
padding: const EdgeInsets.all(70),
child: Image.asset(
'placeholders/placeholder_image.png',
package: 'flutter_gallery_assets',
),
),
),
Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
localizations.demoMotionPlaceholderTitle,
style: textTheme.headlineSmall!.copyWith(
color: Colors.black54,
fontSize: 30,
),
),
const SizedBox(
height: 10,
),
Text(
_loremIpsumParagraph,
style: textTheme.bodyMedium!.copyWith(
color: Colors.black54,
height: 1.5,
fontSize: 16,
),
),
],
),
),
],
),
);
}
}
// END openContainerTransformDemo