mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-30 13:19:44 +02:00
fix(artist): zoom artwork during pull-down stretching
This commit is contained in:
1 parent
39f7f27e35
commit
2cfd2e8a48
2 files changed
+90
-3
No files matched your search
@@ -157,9 +157,10 @@ class MornyeArtistHeader extends StatelessWidget {
|
|||||||
final String? logoUrl;
|
final String? logoUrl;
|
||||||
final Widget? badge;
|
final Widget? badge;
|
||||||
|
|
||||||
|
// A SliverMainAxisGroup clamps negative overlap, preventing this header from
|
||||||
|
// receiving the overscroll used for its stretch animation.
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) =>
|
Widget build(BuildContext context) => buildSlivers(context).single;
|
||||||
SliverMainAxisGroup(slivers: buildSlivers(context));
|
|
||||||
|
|
||||||
List<Widget> buildSlivers(BuildContext context) {
|
List<Widget> buildSlivers(BuildContext context) {
|
||||||
final surface = Theme.of(context).colorScheme.surface;
|
final surface = Theme.of(context).colorScheme.surface;
|
||||||
@@ -206,6 +207,7 @@ class MornyeArtistHeader extends StatelessWidget {
|
|||||||
32;
|
32;
|
||||||
return SliverAppBar(
|
return SliverAppBar(
|
||||||
pinned: true,
|
pinned: true,
|
||||||
|
stretch: !MediaQuery.disableAnimationsOf(context),
|
||||||
expandedHeight: expandedHeight - MediaQuery.paddingOf(context).top,
|
expandedHeight: expandedHeight - MediaQuery.paddingOf(context).top,
|
||||||
backgroundColor: surface,
|
backgroundColor: surface,
|
||||||
surfaceTintColor: Colors.transparent,
|
surfaceTintColor: Colors.transparent,
|
||||||
@@ -233,6 +235,7 @@ class MornyeArtistHeader extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
flexibleSpace: FlexibleSpaceBar(
|
flexibleSpace: FlexibleSpaceBar(
|
||||||
collapseMode: CollapseMode.pin,
|
collapseMode: CollapseMode.pin,
|
||||||
|
stretchModes: const [StretchMode.zoomBackground],
|
||||||
background: Stack(
|
background: Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: [
|
children: [
|
||||||
@@ -366,7 +369,30 @@ class _ArtistCollapsingArtwork extends ConsumerWidget {
|
|||||||
sigmaY: blur,
|
sigmaY: blur,
|
||||||
tileMode: TileMode.clamp,
|
tileMode: TileMode.clamp,
|
||||||
),
|
),
|
||||||
child: RepaintBoundary(child: child),
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final height = settings?.maxExtent ?? constraints.maxHeight;
|
||||||
|
final zoom = height > 0
|
||||||
|
? (constraints.maxHeight / height).clamp(
|
||||||
|
1.0,
|
||||||
|
double.infinity,
|
||||||
|
)
|
||||||
|
: 1.0;
|
||||||
|
// Stretch the photograph uniformly around its top edge.
|
||||||
|
// Identity and actions remain outside this transform, moving
|
||||||
|
// down with the sliver without growing along with the image.
|
||||||
|
return OverflowBox(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
minHeight: height,
|
||||||
|
maxHeight: height,
|
||||||
|
child: Transform.scale(
|
||||||
|
scale: zoom,
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: RepaintBoundary(child: child),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (blurEnabled && fade < 1)
|
if (blurEnabled && fade < 1)
|
||||||
|
|||||||
@@ -222,6 +222,67 @@ void main() {
|
|||||||
expect(tester.takeException(), isNull);
|
expect(tester.takeException(), isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('pulling the artist header zooms only the artwork', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
tester.view.physicalSize = const Size(390, 844);
|
||||||
|
tester.view.devicePixelRatio = 1;
|
||||||
|
tester.view.padding = FakeViewPadding(top: 59, bottom: 34);
|
||||||
|
addTearDown(tester.view.reset);
|
||||||
|
const artworkKey = ValueKey('stretch-artwork');
|
||||||
|
await tester.pumpWidget(
|
||||||
|
ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
theme: MornyeTheme.build(Brightness.dark),
|
||||||
|
home: Scaffold(
|
||||||
|
body: CustomScrollView(
|
||||||
|
physics: const BouncingScrollPhysics(
|
||||||
|
parent: AlwaysScrollableScrollPhysics(),
|
||||||
|
),
|
||||||
|
slivers: const [
|
||||||
|
MornyeArtistHeader(
|
||||||
|
name: 'Artist',
|
||||||
|
artwork: ColoredBox(key: artworkKey, color: Colors.orange),
|
||||||
|
actions: [Text('Artist action')],
|
||||||
|
showTitle: false,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(child: Text('Album list')),
|
||||||
|
SliverToBoxAdapter(child: SizedBox(height: 2000)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final artwork = find.byKey(artworkKey);
|
||||||
|
final action = find.text('Artist action');
|
||||||
|
final albums = find.text('Album list');
|
||||||
|
final originalArt = tester.getRect(artwork);
|
||||||
|
final originalAction = tester.getRect(action);
|
||||||
|
final originalAlbums = tester.getRect(albums);
|
||||||
|
final element = tester.element(artwork);
|
||||||
|
final gesture = await tester.startGesture(const Offset(195, 350));
|
||||||
|
await gesture.moveBy(const Offset(0, 150));
|
||||||
|
await tester.pump();
|
||||||
|
final stretchedArt = tester.getRect(artwork);
|
||||||
|
expect(stretchedArt.width, greaterThan(originalArt.width));
|
||||||
|
expect(
|
||||||
|
stretchedArt.width / originalArt.width,
|
||||||
|
closeTo(stretchedArt.height / originalArt.height, 0.001),
|
||||||
|
);
|
||||||
|
expect(stretchedArt.top, closeTo(originalArt.top, 0.01));
|
||||||
|
expect(tester.getSize(action), originalAction.size);
|
||||||
|
expect(tester.getRect(action).top, greaterThan(originalAction.top));
|
||||||
|
expect(tester.getRect(albums).top, greaterThan(originalAlbums.top));
|
||||||
|
expect(tester.element(artwork), same(element));
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(tester.getRect(artwork), originalArt);
|
||||||
|
expect(tester.getRect(action), originalAction);
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
for (final brightness in Brightness.values) {
|
for (final brightness in Brightness.values) {
|
||||||
for (final scale in [1.0, 2.0]) {
|
for (final scale in [1.0, 2.0]) {
|
||||||
testWidgets(
|
testWidgets(
|
||||||
|
|||||||
Reference in new issue
Block a user