mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-06 11:09:28 +00:00
137 lines
4.7 KiB
Dart
137 lines
4.7 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:whispering_pages/api/image_provider.dart';
|
|
import 'package:whispering_pages/api/library_item_provider.dart';
|
|
import 'package:whispering_pages/extensions/hero_tag_conventions.dart';
|
|
import 'package:whispering_pages/router/models/library_item_extras.dart';
|
|
import 'package:whispering_pages/widgets/shelves/book_shelf.dart';
|
|
|
|
class LibraryItemPage extends HookConsumerWidget {
|
|
const LibraryItemPage({
|
|
super.key,
|
|
required this.itemId,
|
|
this.extra,
|
|
});
|
|
|
|
final String itemId;
|
|
final Object? extra;
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final extraMap =
|
|
extra is LibraryItemExtras ? extra as LibraryItemExtras : null;
|
|
final item = ref.watch(libraryItemProvider(itemId));
|
|
final providedCacheImage = extraMap?.coverImage != null
|
|
? Image.memory(extraMap!.coverImage!)
|
|
: null;
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(),
|
|
body: Center(
|
|
child: Column(
|
|
children: [
|
|
// cover image
|
|
Hero(
|
|
tag: HeroTagPrefixes.bookCover +
|
|
itemId +
|
|
(extraMap?.heroTagSuffix ?? ''),
|
|
child: LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
final width =
|
|
calculateWidth(context, constraints, heightRatio: 0.35);
|
|
return SizedBox(
|
|
height: width,
|
|
width: width,
|
|
child: providedCacheImage ??
|
|
item.when(
|
|
data: (libraryItem) {
|
|
final coverImage =
|
|
ref.watch(coverImageProvider(libraryItem));
|
|
return Stack(
|
|
children: [
|
|
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);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
error: (error, stack) =>
|
|
const CircularProgressIndicator(),
|
|
loading: () =>
|
|
const Center(child: BookCoverSkeleton()),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
|
|
// author
|
|
|
|
// title
|
|
|
|
|
|
// description
|
|
const Text('Description'),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// child: Hero(
|
|
// tag: HeroTagPrefixes.bookCover +
|
|
// itemId +
|
|
// (extraMap?.heroTagSuffix ?? ''),
|
|
// child: Container(
|
|
// color: Colors.amber,
|
|
// height: 200,
|
|
// width: 200,
|
|
// ),
|
|
// ),
|
|
|
|
double calculateWidth(
|
|
BuildContext context,
|
|
BoxConstraints constraints, {
|
|
double heightRatio = 0.25,
|
|
double widthRatio = 0.9,
|
|
}) {
|
|
final availHeight =
|
|
min(constraints.maxHeight, MediaQuery.of(context).size.height);
|
|
final availWidth =
|
|
min(constraints.maxWidth, MediaQuery.of(context).size.width);
|
|
|
|
// make the width 90% of the available width
|
|
var width = availWidth * widthRatio;
|
|
// but never exceed more than 25% of height
|
|
if (width > availHeight * heightRatio) {
|
|
width = availHeight * heightRatio;
|
|
}
|
|
|
|
return width;
|
|
}
|