responsive home_page

This commit is contained in:
Dr-Blank 2024-05-08 21:25:06 -04:00
parent a720c977c2
commit ebc14a0448
No known key found for this signature in database
GPG key ID: 7452CC63F210A266
9 changed files with 171 additions and 85 deletions

View file

@ -12,7 +12,7 @@ class AuthorHomeShelf extends HookConsumerWidget {
required this.title,
});
final Widget title;
final String title;
final AuthorShelf shelf;
@override

View file

@ -1,7 +1,9 @@
import 'package:auto_scroll_text/auto_scroll_text.dart';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
import 'package:shimmer/shimmer.dart' show Shimmer, ShimmerDirection;
import 'package:whispering_pages/api/image_provider.dart';
import 'package:whispering_pages/widgets/shelves/home_shelf.dart';
@ -13,7 +15,7 @@ class BookHomeShelf extends HookConsumerWidget {
required this.title,
});
final Widget title;
final String title;
final LibraryItemShelf shelf;
@override
@ -49,69 +51,94 @@ class BookOnShelf extends HookConsumerWidget {
final book = BookMinified.fromJson(item.media.toJson());
final metadata = BookMetadataMinified.fromJson(book.metadata.toJson());
final coverImage = ref.watch(coverImageProvider(item));
const coverSize = 150.0;
return Container(
margin: const EdgeInsets.only(right: 10, bottom: 10),
constraints: const BoxConstraints(maxWidth: coverSize),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: AspectRatio(
aspectRatio: 1,
child: Container(
constraints: const BoxConstraints(maxWidth: coverSize),
color: Colors.grey[800],
child: coverImage.when(
data: (image) {
if (image.isEmpty) {
return LayoutBuilder(
builder: (context, constraints) {
final height = min(constraints.maxHeight, 500);
final width = height * 0.75;
return SizedBox(
width: width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// the cover image of the book
// take up remaining space
Expanded(
// border radius
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: coverImage.when(
data: (image) {
// return const BookCoverSkeleton();
if (image.isEmpty) {
return const Icon(Icons.error);
}
// cover 80% of parent height
return Image.memory(
image,
fit: BoxFit.cover,
cacheWidth:
(height * MediaQuery.of(context).devicePixelRatio)
.round(),
);
},
loading: () {
return const Center(child: BookCoverSkeleton());
},
error: (error, stack) {
return const Icon(Icons.error);
}
return Image.memory(
image,
fit: BoxFit.cover,
cacheWidth:
(coverSize * MediaQuery.of(context).devicePixelRatio)
.round(),
);
},
loading: () {
return const Center(child: CircularProgressIndicator());
},
error: (error, stack) {
return const Icon(Icons.error);
},
},
),
),
),
),
// the title and author of the book
// AutoScrollText(
Text(
metadata.title ?? '',
// mode: AutoScrollTextMode.bouncing,
// curve: Curves.easeInOut,
// velocity: const Velocity(pixelsPerSecond: Offset(15, 0)),
// delayBefore: const Duration(seconds: 2),
// pauseBetween: const Duration(seconds: 2),
// numberOfReps: 15,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 3),
Text(
metadata.authorName ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodySmall,
),
],
),
Container(
margin: const EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AutoScrollText(
metadata.title ?? '',
mode: AutoScrollTextMode.bouncing,
curve: Curves.easeInOut,
velocity: const Velocity(pixelsPerSecond: Offset(15, 0)),
delayBefore: const Duration(seconds: 2),
pauseBetween: const Duration(seconds: 2),
numberOfReps: 15,
// maxLines: 1,
// overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 3),
Text(
metadata.authorName ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
);
},
);
}
}
// a skeleton for the book cover
class BookCoverSkeleton extends StatelessWidget {
const BookCoverSkeleton({
super.key,
});
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: SizedBox(
width: 150,
child: Shimmer.fromColors(
baseColor: Theme.of(context).colorScheme.surface.withOpacity(0.3),
highlightColor:
Theme.of(context).colorScheme.onSurface.withOpacity(0.1),
child: Container(
color: Theme.of(context).colorScheme.surface,
),
],
),
),
);
}

View file

@ -1,3 +1,5 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
@ -14,7 +16,7 @@ class HomeShelf extends HookConsumerWidget {
required this.title,
});
final Widget title;
final String title;
final Shelf shelf;
@override
@ -33,30 +35,46 @@ class HomeShelf extends HookConsumerWidget {
}
}
/// A shelf that displays books on the home page
/// A shelf that displays children on the home page
class SimpleHomeShelf extends HookConsumerWidget {
const SimpleHomeShelf({
super.key,
required this.children,
required this.title,
this.height,
});
final Widget title;
/// the title of the shelf
final String title;
/// the children to display on the shelf
final List<Widget> children;
final double? height;
@override
Widget build(BuildContext context, WidgetRef ref) {
// if height is null take up 30% of the smallest screen dimension
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title,
Text(title, style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 16),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: children,
SizedBox(
height: max(
min(
height ?? 0.3 * MediaQuery.of(context).size.shortestSide,
200.0,
),
150.0,
),
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => children[index],
separatorBuilder: (context, index) => const SizedBox(width: 16),
itemCount: children.length,
),
),
],