Skip to content

Commit

Permalink
Add missed animes
Browse files Browse the repository at this point in the history
  • Loading branch information
Ziedelth committed May 13, 2024
1 parent 61afa9d commit c455865
Show file tree
Hide file tree
Showing 17 changed files with 559 additions and 23 deletions.
2 changes: 1 addition & 1 deletion lib/components/calendar_anime_component.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:application/components/card_component.dart';
import 'package:application/components/episodes/watchlist_button.dart';
import 'package:application/components/watchlist_button.dart';
import 'package:application/components/image_component.dart';
import 'package:application/components/lang_type_component.dart';
import 'package:application/components/platforms/list_platform.dart';
Expand Down
6 changes: 4 additions & 2 deletions lib/components/card_component.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import 'package:flutter/material.dart';

class CustomCard extends StatefulWidget {
final Widget child;
final Color? backgroundColor;
final Function()? onTap;
final Function(TapDownDetails?)? onLongPress;

const CustomCard({
super.key,
required this.child,
this.backgroundColor,
this.onTap,
this.onLongPress,
});
Expand All @@ -30,9 +32,9 @@ class _CustomCardState extends State<CustomCard> {
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: withOpacity,
color: widget.backgroundColor ?? withOpacity,
border: Border.all(
color: withOpacity,
color: widget.backgroundColor ?? withOpacity,
width: 1,
),
),
Expand Down
2 changes: 1 addition & 1 deletion lib/components/episodes/episode_action_bar.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:application/components/episodes/watchlist_button.dart';
import 'package:application/components/watchlist_button.dart';
import 'package:application/dtos/episode_mapping_dto.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
Expand Down
93 changes: 93 additions & 0 deletions lib/components/missed_anime_component.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import 'package:application/components/card_component.dart';
import 'package:application/components/image_component.dart';
import 'package:application/controllers/missed_anime_controller.dart';
import 'package:application/dtos/missed_anime_dto.dart';
import 'package:application/views/anime_details_view.dart';
import 'package:flutter/material.dart';

class MissedAnimeComponent extends StatelessWidget {
static const bookmarkColor = Colors.yellow;
final MissedAnimeDto missedAnime;

const MissedAnimeComponent({
super.key,
required this.missedAnime,
});

@override
Widget build(BuildContext context) {
return CustomCard(
backgroundColor: Colors.transparent,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => AnimeDetailsView(anime: missedAnime.anime),
),
);
},
onLongPress: (details) {
MissedAnimeController.instance
.onLongPress(context, missedAnime, details);
},
child: SizedBox(
width: 100,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
width: 80,
height: 80,
child: Stack(
children: [
ImageComponent(
uuid: missedAnime.anime.uuid,
borderRadius: BorderRadius.circular(360),
),
Positioned(
top: 0,
right: 0,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 5,
vertical: 2,
),
decoration: const BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child: Text(
missedAnime.episodeMissed >= 10
? '9+'
: missedAnime.episodeMissed.toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
),
],
),
),
const SizedBox(height: 4),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(
missedAnime.anime.shortName,
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
maxLines: 1,
textAlign: TextAlign.center,
),
),
],
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:application/components/followed_stream_builder.dart';
import 'package:application/controllers/member_controller.dart';
import 'package:application/controllers/missed_anime_controller.dart';
import 'package:application/dtos/anime_dto.dart';
import 'package:application/dtos/episode_mapping_dto.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -41,17 +42,25 @@ class WatchlistButton extends StatelessWidget {
onTap: (isLiked) async {
if (!isLiked) {
if (anime != null) {
MemberController.instance.followAnime(anime!);
MemberController.instance
.followAnime(anime!)
.then((value) => MissedAnimeController.instance.init());
} else {
MemberController.instance.followEpisode(episode!);
MemberController.instance
.followEpisode(episode!)
.then((value) => MissedAnimeController.instance.init());
}

Vibration.vibrate(pattern: [0, 50, 125, 50, 125, 50]);
} else {
if (anime != null) {
MemberController.instance.unfollowAnime(anime!);
MemberController.instance
.unfollowAnime(anime!)
.then((value) => MissedAnimeController.instance.init());
} else {
MemberController.instance.unfollowEpisode(episode!);
MemberController.instance
.unfollowEpisode(episode!)
.then((value) => MissedAnimeController.instance.init());
}
}

Expand Down
5 changes: 4 additions & 1 deletion lib/controllers/anime_controller.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';

import 'package:application/controllers/member_controller.dart';
import 'package:application/controllers/missed_anime_controller.dart';
import 'package:application/controllers/simulcast_controller.dart';
import 'package:application/dtos/anime_dto.dart';
import 'package:application/utils/constant.dart';
Expand Down Expand Up @@ -108,7 +109,9 @@ class AnimeController {
],
).then((value) {
if (value == 0) {
MemberController.instance.followAllEpisodes(anime);
MemberController.instance
.followAllEpisodes(anime)
.then((value) => MissedAnimeController.instance.init());
Vibration.vibrate(pattern: [0, 50, 125, 50, 125, 50]);
} else if (value == 1) {
Share.share(
Expand Down
122 changes: 122 additions & 0 deletions lib/controllers/missed_anime_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import 'dart:async';

import 'package:application/controllers/member_controller.dart';
import 'package:application/dtos/missed_anime_dto.dart';
import 'package:application/utils/constant.dart';
import 'package:application/utils/http_request.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:share_plus/share_plus.dart';
import 'package:vibration/vibration.dart';

class MissedAnimeController {
static MissedAnimeController instance = MissedAnimeController();
final missedAnimes = <MissedAnimeDto>[];
final scrollController = ScrollController();
final streamController = StreamController<List<MissedAnimeDto>>.broadcast();
int page = 1;
bool isLoading = false;
bool canLoadMore = true;

Future<void> init() async {
missedAnimes.clear();
streamController.add(missedAnimes);

page = 1;
isLoading = false;
canLoadMore = true;
await nextPage();

scrollController.addListener(() {
// If the user is going to the end of the list
final position = scrollController.position;

if (position.pixels >= position.maxScrollExtent - 300 &&
!isLoading &&
canLoadMore) {
nextPage();
}
});
}

Future<void> goToTop() async {
await scrollController.animateTo(
0,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
);

await init();
}

Future<void> nextPage() async {
if (isLoading) {
return;
}

isLoading = true;

try {
final pageableDto = await HttpRequest.instance.getPage(
'/v1/animes/missed?page=$page&limit=6',
token: MemberController.instance.member!.token,
);

missedAnimes.addAll(
pageableDto.data
.map((e) => MissedAnimeDto.fromJson(e as Map<String, dynamic>)),
);

streamController.add(missedAnimes);
canLoadMore = missedAnimes.length < pageableDto.total;
} catch (e) {
debugPrint(e.toString());
} finally {
isLoading = false;
page++;
}
}

void onLongPress(
BuildContext context,
MissedAnimeDto missedAnime,
TapDownDetails? details,
) {
if (details == null) {
return;
}

final RenderBox renderBox =
Overlay.of(context).context.findRenderObject() as RenderBox;

// Show dropdown menu
showMenu<int>(
context: context,
position: RelativeRect.fromRect(
details.globalPosition & const Size(40, 40),
Offset.zero & renderBox.size,
),
items: [
PopupMenuItem(
value: 0,
child: Text(AppLocalizations.of(context)!.markWatched),
),
PopupMenuItem(
value: 1,
child: Text(AppLocalizations.of(context)!.share),
),
],
).then((value) {
if (value == 0) {
MemberController.instance
.followAllEpisodes(missedAnime.anime)
.then((value) => init());
Vibration.vibrate(pattern: [0, 50, 125, 50, 125, 50]);
} else if (value == 1) {
Share.share(
'${Constant.baseUrl}/animes/${missedAnime.anime.slug}',
);
}
});
}
}
16 changes: 16 additions & 0 deletions lib/dtos/missed_anime_dto.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:application/dtos/anime_dto.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'missed_anime_dto.freezed.dart';
part 'missed_anime_dto.g.dart';

@freezed
class MissedAnimeDto with _$MissedAnimeDto {
const factory MissedAnimeDto({
required AnimeDto anime,
required int episodeMissed,
}) = _MissedAnimeDto;

factory MissedAnimeDto.fromJson(Map<String, dynamic> json) =>
_$MissedAnimeDtoFromJson(json);
}
Loading

0 comments on commit c455865

Please sign in to comment.