import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import '../../models/jellyfin_models.dart'; import '../../models/finamp_models.dart'; import '../../services/finamp_settings_helper.dart'; import '../../services/generate_subtitle.dart'; import '../album_image.dart'; /// Card content for AlbumItem. You probably shouldn't use this widget directly, /// use AlbumItem instead. class AlbumItemCard extends StatelessWidget { const AlbumItemCard({ Key? key, required this.item, this.parentType, this.onTap, this.addSettingsListener = false, }) : super(key: key); final BaseItemDto item; final String? parentType; final void Function()? onTap; final bool addSettingsListener; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return DecoratedBox( decoration: BoxDecoration( borderRadius: BorderRadius.circular(26), boxShadow: [ BoxShadow( color: colorScheme.shadow.withOpacity(0.32), blurRadius: 22, offset: const Offset(0, 12), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(26), child: Stack( children: [ Positioned.fill(child: AlbumImage(item: item)), Positioned.fill( child: DecoratedBox( decoration: BoxDecoration( border: Border.all( color: Colors.white.withOpacity(0.10), ), borderRadius: BorderRadius.circular(26), ), ), ), addSettingsListener ? // We need this ValueListenableBuilder to react to changes to // showTextOnGridView. When shown in a MusicScreen, this widget // would refresh anyway since MusicScreen also listens to // FinampSettings, but there may be cases where this widget is used // elsewhere. ValueListenableBuilder>( valueListenable: FinampSettingsHelper.finampSettingsListener, builder: (_, box, __) { if (box.get("FinampSettings")!.showTextOnGridView) { return _AlbumItemCardText( item: item, parentType: parentType); } else { // ValueListenableBuilder doesn't let us return null, so we // return a 0-sized SizedBox. return const SizedBox.shrink(); } }, ) : FinampSettingsHelper.finampSettings.showTextOnGridView ? _AlbumItemCardText(item: item, parentType: parentType) : const SizedBox.shrink(), Positioned.fill( child: Material( color: Colors.transparent, child: InkWell( onTap: onTap, ), ), ) ], ), ), ); } } class _AlbumItemCardText extends StatelessWidget { const _AlbumItemCardText({ Key? key, required this.item, required this.parentType, }) : super(key: key); final BaseItemDto item; final String? parentType; @override Widget build(BuildContext context) { final subtitle = generateSubtitle(item, parentType, context); return Align( alignment: Alignment.bottomCenter, child: Container( width: double.infinity, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, colors: [ Colors.black.withOpacity(0.86), Colors.black.withOpacity(0.24), Colors.transparent, ], stops: const [0.0, 0.58, 1.0], ), ), child: Padding( padding: const EdgeInsets.fromLTRB(14, 46, 14, 14), child: Align( alignment: Alignment.bottomLeft, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.name ?? "Unknown Name", overflow: TextOverflow.ellipsis, maxLines: 2, style: Theme.of(context).textTheme.titleMedium!.copyWith( color: Colors.white, fontWeight: FontWeight.w800, height: 1.05, ), ), if (subtitle != null) Text( subtitle, maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context) .textTheme .bodySmall! .copyWith(color: Colors.white.withOpacity(0.72)), ) ], ), ), ), ), ); } }