Initial commit

This commit is contained in:
2023-02-03 23:33:21 +01:00
commit ee4458d613
147 changed files with 5860 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
import 'package:anitrack/src/data/anime.dart';
import 'package:anitrack/src/ui/widgets/swipe_icon.dart';
import 'package:flutter/material.dart';
import 'package:swipeable_tile/swipeable_tile.dart';
/// A widget for displaying simple data about an anime in the listview
class AnimeListWidget extends StatelessWidget {
const AnimeListWidget({
required this.data,
required this.onLeftSwipe,
required this.onRightSwipe,
super.key,
});
/// The anime to display
final AnimeTrackingData data;
/// Callbacks for the swipe functionality
final void Function() onLeftSwipe;
final void Function() onRightSwipe;
@override
Widget build(BuildContext context) {
return SwipeableTile.swipeToTrigger(
onSwiped: (direction) {
if (direction == SwipeDirection.endToStart) {
onRightSwipe();
} else if (direction == SwipeDirection.startToEnd) {
onLeftSwipe();
}
},
// TODO(PapaTutuWawa): Fix
key: UniqueKey(),
backgroundBuilder: (_, direction, __) {
if (direction == SwipeDirection.endToStart) {
return Align(
alignment: Alignment.centerRight,
child: SwipeIcon(
Icons.add,
),
);
} else if (direction == SwipeDirection.startToEnd) {
return Align(
alignment: Alignment.centerLeft,
child: SwipeIcon(
Icons.remove,
),
);
}
return Container();
},
color: Theme.of(context).scaffoldBackgroundColor,
direction: SwipeDirection.horizontal,
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: SizedBox(
width: 100,
child: Image.network(
data.thumbnailUrl,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
data.title,
style: Theme.of(context).textTheme.titleLarge,
maxLines: 2,
softWrap: true,
overflow: TextOverflow.ellipsis,
),
Text(
'${data.episodesWatched}/${data.episodesTotal ?? "???"}',
style: Theme.of(context).textTheme.titleMedium,
),
],
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
class AnimeCoverImage extends StatelessWidget {
const AnimeCoverImage({
required this.url,
super.key,
});
/// The URL to the cover image.
final String url;
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: SizedBox(
height: 100 * (16 / 9),
width: 100,
child: DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(url),
fit: BoxFit.cover,
),
),
),
),
);
}
}

View File

@@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
/// An icon that is below an anime list item
class SwipeIcon extends StatelessWidget {
const SwipeIcon(
this.icon, {
super.key,
});
/// The icon to display
final IconData icon;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Icon(
icon,
size: 32,
),
);
}
}