♻️ Unified the track tile widget
This commit is contained in:
@@ -355,29 +355,35 @@ class _DesktopMiniPlayer extends HookConsumerWidget {
|
||||
),
|
||||
const Gap(8),
|
||||
// Title & Artist
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12.0,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
currentMetadata?.title ??
|
||||
Uri.parse(media.uri).pathSegments.last,
|
||||
style: Theme.of(context).textTheme.bodyMedium
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
Text(
|
||||
currentMetadata?.artist ?? 'Unknown Artist',
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
Flexible(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12.0,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
currentMetadata?.title ??
|
||||
Uri.parse(media.uri).pathSegments.last,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
Text(
|
||||
currentMetadata?.artist ?? 'Unknown Artist',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodySmall,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:groovybox/data/db.dart' as db;
|
||||
import 'package:groovybox/ui/widgets/universal_image.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
class TrackTile extends StatelessWidget {
|
||||
final db.Track track;
|
||||
@@ -41,29 +41,20 @@ class TrackTile extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: ListTile(
|
||||
contentPadding:
|
||||
padding ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
contentPadding: padding ?? const EdgeInsets.symmetric(horizontal: 16),
|
||||
leading: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
?leading,
|
||||
AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[800],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
image: track.artUri != null
|
||||
? DecorationImage(
|
||||
image: FileImage(File(track.artUri!)),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: track.artUri == null
|
||||
? const Icon(Icons.music_note, color: Colors.white54)
|
||||
: null,
|
||||
),
|
||||
child: UniversalImage(
|
||||
uri: track.artUri,
|
||||
fit: BoxFit.cover,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
fallbackIcon: Icons.music_note,
|
||||
fallbackIconSize: 24,
|
||||
).clipRRect(all: 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
130
lib/ui/widgets/universal_image.dart
Normal file
130
lib/ui/widgets/universal_image.dart
Normal file
@@ -0,0 +1,130 @@
|
||||
import 'dart:io';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class UniversalImage extends StatelessWidget {
|
||||
final String? uri;
|
||||
final BoxFit? fit;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final Widget? fallback;
|
||||
final IconData? fallbackIcon;
|
||||
final double? fallbackIconSize;
|
||||
final Color? fallbackIconColor;
|
||||
final BorderRadius? borderRadius;
|
||||
final bool useDecorationImage;
|
||||
|
||||
const UniversalImage({
|
||||
super.key,
|
||||
this.uri,
|
||||
this.fit = BoxFit.cover,
|
||||
this.width,
|
||||
this.height,
|
||||
this.fallback,
|
||||
this.fallbackIcon = Icons.image,
|
||||
this.fallbackIconSize = 48,
|
||||
this.fallbackIconColor = Colors.white54,
|
||||
this.borderRadius,
|
||||
this.useDecorationImage = false,
|
||||
});
|
||||
|
||||
bool _isNetworkUri(String uri) {
|
||||
return uri.startsWith('http://') || uri.startsWith('https://');
|
||||
}
|
||||
|
||||
Widget _buildFallback() {
|
||||
if (fallback != null) {
|
||||
return fallback!;
|
||||
}
|
||||
|
||||
final icon = Icon(
|
||||
fallbackIcon,
|
||||
size: fallbackIconSize,
|
||||
color: fallbackIconColor,
|
||||
);
|
||||
|
||||
if (borderRadius != null) {
|
||||
return Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[800],
|
||||
borderRadius: borderRadius,
|
||||
),
|
||||
child: icon,
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
width: width,
|
||||
height: height,
|
||||
color: Colors.grey[800],
|
||||
child: icon,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNetworkImage() {
|
||||
if (useDecorationImage) {
|
||||
return CachedNetworkImage(
|
||||
imageUrl: uri!,
|
||||
fit: fit,
|
||||
width: width,
|
||||
height: height,
|
||||
placeholder: (context, url) => Container(
|
||||
width: width,
|
||||
height: height,
|
||||
color: Colors.grey[800],
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
errorWidget: (context, url, error) => _buildFallback(),
|
||||
);
|
||||
}
|
||||
|
||||
return CachedNetworkImage(
|
||||
imageUrl: uri!,
|
||||
fit: fit,
|
||||
width: width,
|
||||
height: height,
|
||||
placeholder: (context, url) => Container(
|
||||
width: width,
|
||||
height: height,
|
||||
color: Colors.grey[800],
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
errorWidget: (context, url, error) => _buildFallback(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFileImage() {
|
||||
if (useDecorationImage) {
|
||||
return Image.file(
|
||||
File(uri!),
|
||||
fit: fit,
|
||||
width: width,
|
||||
height: height,
|
||||
errorBuilder: (context, error, stackTrace) => _buildFallback(),
|
||||
);
|
||||
}
|
||||
|
||||
return Image.file(
|
||||
File(uri!),
|
||||
fit: fit,
|
||||
width: width,
|
||||
height: height,
|
||||
errorBuilder: (context, error, stackTrace) => _buildFallback(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (uri == null || uri!.isEmpty) {
|
||||
return _buildFallback();
|
||||
}
|
||||
|
||||
if (_isNetworkUri(uri!)) {
|
||||
return _buildNetworkImage();
|
||||
} else {
|
||||
return _buildFileImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user