blob: 77d25dd7d189e751347fbc33305f835eb2ea363f [file] [log] [blame]
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:gallery/layout/adaptive.dart';
import 'package:gallery/studies/reply/colors.dart';
import 'package:gallery/studies/reply/mail_view_page.dart';
import 'package:gallery/studies/reply/model/email_model.dart';
import 'package:gallery/studies/reply/model/email_store.dart';
import 'package:gallery/studies/reply/profile_avatar.dart';
import 'package:provider/provider.dart';
const _assetsPackage = 'flutter_gallery_assets';
const _iconAssetLocation = 'reply/icons';
class MailPreviewCard extends StatelessWidget {
const MailPreviewCard({
Key key,
@required this.id,
@required this.email,
@required this.onDelete,
@required this.onStar,
}) : assert(id != null),
assert(email != null),
super(key: key);
final int id;
final Email email;
final VoidCallback onDelete;
final VoidCallback onStar;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final currentEmailStarred = Provider.of<EmailStore>(
context,
listen: false,
).isEmailStarred(email);
return OpenContainer(
openBuilder: (context, closedContainer) {
return MailViewPage(id: id, email: email);
},
openColor: theme.cardColor,
closedShape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(0)),
),
closedElevation: 0,
closedColor: theme.cardColor,
closedBuilder: (context, openContainer) {
final isDesktop = isDisplayDesktop(context);
final colorScheme = theme.colorScheme;
final mailPreview = _MailPreview(
id: id,
email: email,
onTap: openContainer,
onStar: onStar,
onDelete: onDelete,
);
final onStarredInbox = Provider.of<EmailStore>(
context,
listen: false,
).currentlySelectedInbox ==
'Starred';
if (isDesktop) {
return mailPreview;
} else {
return Dismissible(
key: ObjectKey(email),
dismissThresholds: const {
DismissDirection.startToEnd: 0.8,
DismissDirection.endToStart: 0.4,
},
onDismissed: (direction) {
switch (direction) {
case DismissDirection.endToStart:
if (onStarredInbox) {
onStar();
}
break;
case DismissDirection.startToEnd:
onDelete();
break;
default:
}
},
background: _DismissibleContainer(
icon: 'twotone_delete',
backgroundColor: colorScheme.primary,
iconColor: ReplyColors.blue50,
alignment: Alignment.centerLeft,
padding: const EdgeInsetsDirectional.only(start: 20),
),
confirmDismiss: (direction) async {
if (direction == DismissDirection.endToStart) {
if (onStarredInbox) {
return true;
}
onStar();
return false;
} else {
return true;
}
},
secondaryBackground: _DismissibleContainer(
icon: 'twotone_star',
backgroundColor: currentEmailStarred
? colorScheme.secondary
: theme.scaffoldBackgroundColor,
iconColor: currentEmailStarred
? colorScheme.onSecondary
: colorScheme.onBackground,
alignment: Alignment.centerRight,
padding: const EdgeInsetsDirectional.only(end: 20),
),
child: mailPreview,
);
}
},
);
}
}
class _DismissibleContainer extends StatelessWidget {
const _DismissibleContainer({
@required this.icon,
@required this.backgroundColor,
@required this.iconColor,
@required this.alignment,
@required this.padding,
}) : assert(icon != null),
assert(backgroundColor != null),
assert(iconColor != null),
assert(alignment != null),
assert(padding != null);
final String icon;
final Color backgroundColor;
final Color iconColor;
final Alignment alignment;
final EdgeInsetsDirectional padding;
@override
Widget build(BuildContext context) {
return AnimatedContainer(
alignment: alignment,
curve: standardEasing,
color: backgroundColor,
duration: kThemeAnimationDuration,
padding: padding,
child: Material(
color: Colors.transparent,
child: ImageIcon(
AssetImage(
'reply/icons/$icon.png',
package: 'flutter_gallery_assets',
),
size: 36,
color: iconColor,
),
),
);
}
}
class _MailPreview extends StatelessWidget {
const _MailPreview({
@required this.id,
@required this.email,
@required this.onTap,
this.onStar,
this.onDelete,
}) : assert(id != null),
assert(email != null),
assert(onTap != null);
final int id;
final Email email;
final VoidCallback onTap;
final VoidCallback onStar;
final VoidCallback onDelete;
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
var emailStore = Provider.of<EmailStore>(
context,
listen: false,
);
return InkWell(
onTap: () {
Provider.of<EmailStore>(
context,
listen: false,
).currentlySelectedEmailId = id;
onTap();
},
child: LayoutBuilder(
builder: (context, constraints) {
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: constraints.maxHeight),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'${email.sender} - ${email.time}',
style: textTheme.caption,
),
const SizedBox(height: 4),
Text(email.subject, style: textTheme.headline5),
const SizedBox(height: 16),
],
),
),
_MailPreviewActionBar(
avatar: email.avatar,
isStarred: emailStore.isEmailStarred(email),
onStar: onStar,
onDelete: onDelete,
),
],
),
Padding(
padding: const EdgeInsetsDirectional.only(
end: 20,
),
child: Text(
email.message,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: textTheme.bodyText2,
),
),
if (email.containsPictures) ...[
Flexible(
fit: FlexFit.loose,
child: Column(
children: const [
SizedBox(height: 20),
_PicturePreview(),
],
),
),
],
],
),
),
);
},
),
);
}
}
class _PicturePreview extends StatelessWidget {
const _PicturePreview();
@override
Widget build(BuildContext context) {
return SizedBox(
height: 96,
child: ListView.builder(
itemCount: 4,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsetsDirectional.only(end: 4),
child: Image.asset(
'reply/attachments/paris_${index + 1}.jpg',
gaplessPlayback: true,
package: 'flutter_gallery_assets',
),
);
},
),
);
}
}
class _MailPreviewActionBar extends StatelessWidget {
const _MailPreviewActionBar({
@required this.avatar,
this.isStarred,
this.onStar,
this.onDelete,
}) : assert(avatar != null);
final String avatar;
final bool isStarred;
final VoidCallback onStar;
final VoidCallback onDelete;
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final color = isDark ? ReplyColors.white50 : ReplyColors.blue600;
final isDesktop = isDisplayDesktop(context);
final starredIconColor =
isStarred ? Theme.of(context).colorScheme.secondary : color;
return Row(
children: [
if (isDesktop) ...[
IconButton(
icon: ImageIcon(
const AssetImage(
'$_iconAssetLocation/twotone_star.png',
package: _assetsPackage,
),
color: starredIconColor,
),
onPressed: onStar,
),
IconButton(
icon: ImageIcon(
const AssetImage(
'$_iconAssetLocation/twotone_delete.png',
package: _assetsPackage,
),
color: color,
),
onPressed: onDelete,
),
IconButton(
icon: Icon(
Icons.more_vert,
color: color,
),
onPressed: () {},
),
const SizedBox(width: 12),
],
ProfileAvatar(avatar: avatar),
],
);
}
}