mangayomi-mirror/lib/modules/calendar/widgets/upcoming_item.dart
Moustapha Kodjo Amadou 95a55d5f81 feat: Implement upcoming manga calendar feature
- Added UpcomingUIModel for managing upcoming manga list items with headers and items.
- Introduced CalendarDay widget to display individual days with event indicators.
- Created CalendarHeader widget for navigating between months.
- Developed CalendarIndicator for visualizing events on specific days.
- Implemented UpcomingCalendar to manage the calendar view and event loading.
- Added UpcomingItem widget for displaying individual upcoming manga with cover images.
- Introduced FetchInterval utility to calculate fetch intervals based on chapter upload dates.
- Refactored updateMangaDetail to utilize FetchInterval for smart update days.
- Enhanced MedianExtension to ensure correct median calculation.
- Removed unused imports and commented-out code for cleaner implementation.
2026-03-05 12:05:29 +01:00

79 lines
2.4 KiB
Dart

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/widgets/custom_extended_image_provider.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:mangayomi/utils/headers.dart';
const _upcomingItemHeight = 96.0;
class UpcomingItem extends ConsumerWidget {
final Manga manga;
final VoidCallback onTap;
const UpcomingItem({required this.manga, required this.onTap, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
return InkWell(
onTap: onTap,
child: SizedBox(
height: _upcomingItemHeight,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
// Cover image
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: SizedBox(
width: 56,
height: _upcomingItemHeight - 16,
child: Image(
image: _getImageProvider(ref),
fit: BoxFit.cover,
errorBuilder: (_, _, _) => Container(
color: theme.colorScheme.surfaceContainerHighest,
child: const Icon(Icons.broken_image, size: 24),
),
),
),
),
const SizedBox(width: 16),
// Title
Expanded(
child: Text(
manga.name ?? '',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
),
],
),
),
),
);
}
ImageProvider _getImageProvider(WidgetRef ref) {
if (manga.customCoverImage != null) {
return MemoryImage(manga.customCoverImage as Uint8List);
}
return CustomExtendedNetworkImageProvider(
toImgUrl(manga.customCoverFromTracker ?? manga.imageUrl ?? ''),
headers: ref.watch(
headersProvider(
source: manga.source ?? '',
lang: manga.lang ?? '',
sourceId: manga.sourceId,
),
),
);
}
}