mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-14 15:09:29 +00:00
148 lines
4.2 KiB
Dart
148 lines
4.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:vaani/api/library_item_provider.dart';
|
|
import 'package:vaani/shared/extensions/model_conversions.dart';
|
|
|
|
class LibraryItemMetadata extends HookConsumerWidget {
|
|
const LibraryItemMetadata({
|
|
super.key,
|
|
required this.id,
|
|
});
|
|
|
|
final String id;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final item = ref.watch(libraryItemProvider(id)).valueOrNull;
|
|
|
|
/// formats the duration of the book as `10h 30m`
|
|
///
|
|
/// will add up all the durations of the audio files first
|
|
/// then convert them to the given format
|
|
String? getDurationFormatted() {
|
|
final book = (item?.media.asBookExpanded);
|
|
if (book == null) {
|
|
return null;
|
|
}
|
|
final duration = book.audioFiles
|
|
.map((e) => e.duration)
|
|
.reduce((value, element) => value + element);
|
|
final hours = duration.inHours;
|
|
final minutes = duration.inMinutes.remainder(60);
|
|
return '${hours}h ${minutes}m';
|
|
}
|
|
|
|
/// will return the size of the book in MB
|
|
///
|
|
/// will add up all the sizes of the audio files first
|
|
/// then convert them to MB
|
|
String? getSizeFormatted() {
|
|
final book = (item?.media.asBookExpanded);
|
|
if (book == null) {
|
|
return null;
|
|
}
|
|
final size = book.audioFiles
|
|
.map((e) => e.metadata.size)
|
|
.reduce((value, element) => value + element);
|
|
return '${size / 1024 ~/ 1024} MB';
|
|
}
|
|
|
|
/// will return the codec and bitrate of the book
|
|
String? getCodecAndBitrate() {
|
|
final book = (item?.media.asBookExpanded);
|
|
if (book == null) {
|
|
return null;
|
|
}
|
|
final codec = book.audioFiles.first.codec.toUpperCase();
|
|
// final bitrate = book.audioFiles.first.bitRate;
|
|
return codec;
|
|
}
|
|
|
|
final itemBookMetadata = item?.media.metadata.asBookMetadataExpanded;
|
|
|
|
final children = [
|
|
// duration of the book
|
|
_MetadataItem(
|
|
title: switch (itemBookMetadata?.abridged) {
|
|
true => 'Abridged',
|
|
false => 'Unabridged',
|
|
_ => 'Length',
|
|
},
|
|
value: getDurationFormatted() ?? 'time is just a concept',
|
|
),
|
|
_MetadataItem(
|
|
title: 'Published',
|
|
value: itemBookMetadata?.publishedDate ??
|
|
itemBookMetadata?.publishedYear ??
|
|
'Unknown',
|
|
),
|
|
_MetadataItem(
|
|
title: getCodecAndBitrate() ?? 'Codec & Bitrate',
|
|
value: getSizeFormatted() ?? 'Unknown',
|
|
),
|
|
];
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
child: IntrinsicHeight(
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
// alternate between metadata and vertical divider
|
|
children: List.generate(
|
|
children.length * 2 - 1,
|
|
(index) {
|
|
if (index.isEven) {
|
|
return children[index ~/ 2];
|
|
}
|
|
return VerticalDivider(
|
|
indent: 6,
|
|
endIndent: 6,
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.onSurface
|
|
.withValues(alpha: 0.6),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// key-value pair to display as column
|
|
class _MetadataItem extends StatelessWidget {
|
|
const _MetadataItem({
|
|
required this.title,
|
|
required this.value,
|
|
});
|
|
|
|
final String title;
|
|
final String value;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final themeData = Theme.of(context);
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
style: themeData.textTheme.titleMedium?.copyWith(
|
|
color: themeData.colorScheme.onSurface.withValues(alpha: 0.90),
|
|
),
|
|
value,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
Text(
|
|
style: themeData.textTheme.bodySmall?.copyWith(
|
|
color: themeData.colorScheme.onSurface.withValues(alpha: 0.7),
|
|
),
|
|
title,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|