95 lines
2.6 KiB
Dart
95 lines
2.6 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
|
import 'package:go_router/go_router.dart';
|
||
|
|
|
||
|
|
import '../../../core/contracts/library.dart';
|
||
|
|
import '../../../providers/emby_headers_provider.dart';
|
||
|
|
import '../../../providers/session_provider.dart';
|
||
|
|
import '../../../shared/mappers/media_image_url.dart';
|
||
|
|
import '../../../shared/widgets/cast_scroller.dart';
|
||
|
|
import 'section_container.dart';
|
||
|
|
|
||
|
|
class EmbyCastSection extends ConsumerWidget {
|
||
|
|
final EmbyRawItem item;
|
||
|
|
final bool embedded;
|
||
|
|
|
||
|
|
|
||
|
|
final Widget? leading;
|
||
|
|
|
||
|
|
const EmbyCastSection({
|
||
|
|
super.key,
|
||
|
|
required this.item,
|
||
|
|
this.embedded = false,
|
||
|
|
this.leading,
|
||
|
|
});
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
||
|
|
final people = _extractActors(item);
|
||
|
|
if (people.isEmpty) return const SizedBox.shrink();
|
||
|
|
|
||
|
|
final session = ref.watch(activeSessionProvider);
|
||
|
|
if (session == null) return const SizedBox.shrink();
|
||
|
|
|
||
|
|
final headers = ref.watch(embyImageHeadersProvider).value;
|
||
|
|
final hPad = embedded ? 0.0 : SectionContainer.hPadOf(context);
|
||
|
|
|
||
|
|
final entries = people.map((person) {
|
||
|
|
final name = person['Name'] as String? ?? '';
|
||
|
|
final role = person['Role'] as String?;
|
||
|
|
final personId = person['Id'] as String?;
|
||
|
|
final imageTag = person['PrimaryImageTag'] as String?;
|
||
|
|
|
||
|
|
final photoUrl = personId != null
|
||
|
|
? _personImageUrl(
|
||
|
|
session.serverUrl,
|
||
|
|
session.token,
|
||
|
|
personId,
|
||
|
|
imageTag,
|
||
|
|
)
|
||
|
|
: null;
|
||
|
|
final tappable = personId != null && personId.isNotEmpty;
|
||
|
|
|
||
|
|
return CastEntry(
|
||
|
|
name: name,
|
||
|
|
subtitle: role,
|
||
|
|
imageUrl: photoUrl,
|
||
|
|
imageHeaders: headers,
|
||
|
|
onTap: tappable ? () => context.push('/person/$personId') : null,
|
||
|
|
);
|
||
|
|
}).toList();
|
||
|
|
|
||
|
|
return SectionContainer(
|
||
|
|
title: '演职人员',
|
||
|
|
embedded: embedded,
|
||
|
|
leadingDivider: embedded,
|
||
|
|
leading: leading,
|
||
|
|
child: CastScroller(
|
||
|
|
entries: entries,
|
||
|
|
padding: EdgeInsets.symmetric(horizontal: hPad),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
static List<Map<String, dynamic>> _extractActors(EmbyRawItem item) {
|
||
|
|
final raw = item.extra['People'];
|
||
|
|
if (raw is! List) return const [];
|
||
|
|
return raw.whereType<Map<String, dynamic>>().toList();
|
||
|
|
}
|
||
|
|
|
||
|
|
static String? _personImageUrl(
|
||
|
|
String baseUrl,
|
||
|
|
String token,
|
||
|
|
String personId,
|
||
|
|
String? tag,
|
||
|
|
) {
|
||
|
|
if (tag == null) return null;
|
||
|
|
return EmbyImageUrl.primaryById(
|
||
|
|
baseUrl: baseUrl,
|
||
|
|
token: token,
|
||
|
|
itemId: personId,
|
||
|
|
maxHeight: 200,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|