feat(ui): Implement a Hero transition

This commit is contained in:
PapaTutuWawa 2023-02-08 20:24:31 +01:00
parent bea3ff8b78
commit e12b9a0c72
4 changed files with 80 additions and 67 deletions

View File

@ -159,23 +159,24 @@ class AnimeListPage extends StatelessWidget {
); );
}, },
child: AnimeCoverImage( child: AnimeCoverImage(
url: anime.thumbnailUrl, url: anime.thumbnailUrl,
onTap: () { hero: anime.id,
context.read<DetailsBloc>().add( onTap: () {
AnimeDetailsRequestedEvent(anime), context.read<DetailsBloc>().add(
); AnimeDetailsRequestedEvent(anime),
}, );
extra: Align( },
alignment: Alignment.centerRight, extra: Align(
child: Padding( alignment: Alignment.centerRight,
padding: const EdgeInsets.only(right: 8), child: Padding(
child: Text( padding: const EdgeInsets.only(right: 8),
'${anime.episodesWatched}/${anime.episodesTotal ?? "???"}', child: Text(
style: Theme.of(context).textTheme.titleMedium, '${anime.episodesWatched}/${anime.episodesTotal ?? "???"}',
style: Theme.of(context).textTheme.titleMedium,
),
), ),
), ),
), ),
),
); );
}, },
), ),
@ -208,23 +209,24 @@ class AnimeListPage extends StatelessWidget {
); );
}, },
child: AnimeCoverImage( child: AnimeCoverImage(
url: manga.thumbnailUrl, hero: manga.id,
onTap: () { url: manga.thumbnailUrl,
context.read<DetailsBloc>().add( onTap: () {
MangaDetailsRequestedEvent(manga), context.read<DetailsBloc>().add(
); MangaDetailsRequestedEvent(manga),
}, );
extra: Align( },
alignment: Alignment.centerRight, extra: Align(
child: Padding( alignment: Alignment.centerRight,
padding: const EdgeInsets.only(right: 8), child: Padding(
child: Text( padding: const EdgeInsets.only(right: 8),
'${manga.chaptersRead}/${manga.chaptersTotal ?? "???"}', child: Text(
style: Theme.of(context).textTheme.titleMedium, '${manga.chaptersRead}/${manga.chaptersTotal ?? "???"}',
style: Theme.of(context).textTheme.titleMedium,
),
), ),
), ),
), ),
),
); );
}, },
), ),

View File

@ -38,9 +38,9 @@ class DetailsPage extends StatelessWidget {
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [AnimeCoverImage(
AnimeCoverImage( url: state.data!.thumbnailUrl,
url: state.data!.thumbnailUrl, hero: state.data!.id,
), ),
Expanded( Expanded(

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
class AnimeCoverImage extends StatelessWidget { class AnimeCoverImage extends StatelessWidget {
const AnimeCoverImage({ const AnimeCoverImage({
required this.url, required this.url,
required this.hero,
this.cached = true, this.cached = true,
this.extra, this.extra,
this.onTap, this.onTap,
@ -16,6 +17,9 @@ class AnimeCoverImage extends StatelessWidget {
/// Flag indicating if the image should be cached. /// Flag indicating if the image should be cached.
final bool cached; final bool cached;
/// The hero tag of the image.
final String hero;
/// An extra widget with a translucent backdrop. /// An extra widget with a translucent backdrop.
final Widget? extra; final Widget? extra;
@ -24,46 +28,51 @@ class AnimeCoverImage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ClipRRect( return Hero(
borderRadius: BorderRadius.circular(8), tag: hero,
child: SizedBox( child: ClipRRect(
height: 100 * (16 / 9), borderRadius: BorderRadius.circular(8),
width: 120, child: Material(
child: InkWell( child: SizedBox(
onTap: onTap ?? () {}, height: 100 * (16 / 9),
child: Stack( width: 120,
children: [ child: InkWell(
Positioned( onTap: onTap ?? () {},
left: 0, child: Stack(
right: 0, children: [
top: 0, Positioned(
bottom: 0, left: 0,
child: DecoratedBox( right: 0,
decoration: BoxDecoration( top: 0,
image: DecorationImage( bottom: 0,
image: cached ? child: DecoratedBox(
CachedNetworkImageProvider(url) as ImageProvider : decoration: BoxDecoration(
NetworkImage(url), image: DecorationImage(
fit: BoxFit.cover, image: cached ?
CachedNetworkImageProvider(url) as ImageProvider :
NetworkImage(url),
fit: BoxFit.cover,
),
),
), ),
), ),
),
),
if (extra != null) if (extra != null)
Positioned( Positioned(
left: 0, left: 0,
bottom: 0, bottom: 0,
right: 0, right: 0,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: ColoredBox( child: ColoredBox(
color: Colors.black54, color: Colors.black54,
child: extra, child: extra,
),
),
), ),
), ],
), ),
], ),
), ),
), ),
), ),

View File

@ -76,6 +76,8 @@ class ListItem extends StatelessWidget {
children: [ children: [
AnimeCoverImage( AnimeCoverImage(
cached: cached, cached: cached,
// TODO(Unknown): Have the ID here
hero: thumbnailUrl,
extra: imageExtra, extra: imageExtra,
url: thumbnailUrl, url: thumbnailUrl,
), ),