Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
d2bfa66
Marge (#38)
Shebyyy Feb 1, 2026
65fc614
Merge branch 'RyanYuuki:main' into beta2
Shebyyy Feb 1, 2026
5390551
Feat : New Visuals popup (#39)
NITHINSPACETIME Feb 3, 2026
cec1b1c
chore: address Copilot PR reviews (cleanup imports, improve error log…
NITHINSPACETIME Feb 3, 2026
1f20606
doc: added beta things
Shebyyy Feb 3, 2026
a814cfd
fix : added logic to filter anime-only
NITHINSPACETIME Feb 3, 2026
0dbee68
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 5, 2026
0f0a6ca
ADDED BETA THING
Shebyyy Feb 6, 2026
e973c9e
Create manual beta build workflow for Android APKs
Shebyyy Feb 6, 2026
8fd1e89
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 6, 2026
02fb6d4
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 9, 2026
2131b6d
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 9, 2026
142789f
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 9, 2026
9cd00ab
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 9, 2026
b727184
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 9, 2026
0e43f0a
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 11, 2026
2594eef
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 12, 2026
d243b62
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 15, 2026
58113e2
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 15, 2026
97e4574
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 16, 2026
67d8ab4
feat: add beta versioning with custom display and fix logo cropping
Shebyyy Feb 16, 2026
929f87e
Merge branch 'RyanYuuki:main' into beta
Shebyyy Feb 16, 2026
24d0f53
Update anilist_profile.dart
itsmechinmoy Feb 17, 2026
71c50c4
Update profile_page.dart
itsmechinmoy Feb 17, 2026
3a31a6d
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
055b2a4
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
2f2242f
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
62251fc
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
8f70fc8
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
25f9a5a
Token (#46)
itsmechinmoy Feb 17, 2026
ae8b237
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
aee356b
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
1ef6310
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
3f56643
Update profile_page.dart
itsmechinmoy Feb 17, 2026
81c5ec3
Update anilist_profile.dart
itsmechinmoy Feb 17, 2026
91963bd
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
8194d0c
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
3aa1e36
Update profile_page.dart
itsmechinmoy Feb 17, 2026
cbf18c8
Update profile_page.dart
itsmechinmoy Feb 17, 2026
b9c5254
Merge branch 'testing' into token
itsmechinmoy Feb 17, 2026
24212ff
Token (#47)
itsmechinmoy Feb 17, 2026
7ba9945
Update profile_page.dart
itsmechinmoy Feb 17, 2026
af17972
Delete .github/workflows/beta_manual.yml
itsmechinmoy Feb 17, 2026
55f3ca2
Update Notify.yml
itsmechinmoy Feb 17, 2026
f4f0d07
Update build.yml
itsmechinmoy Feb 17, 2026
155f0dd
Update changelog.yaml
itsmechinmoy Feb 17, 2026
222c2ad
Update rename_app.sh
itsmechinmoy Feb 17, 2026
ab9051d
Update anilist_profile.dart
itsmechinmoy Feb 17, 2026
f826d6d
Update profile_page.dart
itsmechinmoy Feb 17, 2026
576b869
Merge branch 'testing' into token
itsmechinmoy Feb 17, 2026
8b4fe5a
Update anilist_auth.dart
itsmechinmoy Feb 17, 2026
663b4ca
Update anilist_profile.dart
itsmechinmoy Feb 17, 2026
f1c682a
Update profile_page.dart
itsmechinmoy Feb 17, 2026
6ed1e80
Update profile_page.dart
itsmechinmoy Feb 17, 2026
44812b1
Update profile_page.dart
itsmechinmoy Feb 17, 2026
0ec4b7f
Update profile_page.dart
itsmechinmoy Feb 18, 2026
51bb340
Update profile_page.dart
itsmechinmoy Feb 18, 2026
420b6b5
Create al_about_me.dart
itsmechinmoy Feb 18, 2026
3d245d3
Merge upstream/main into token and resolve conflicts
NITHINSPACETIME Feb 23, 2026
c68b6b9
fix : error fetching detailes for VA/char
NITHINSPACETIME Feb 24, 2026
339d261
fix : improved and fixed anime detail page + some other fixes (ui tes…
NITHINSPACETIME Feb 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 101 additions & 14 deletions lib/controllers/services/anilist/anilist_auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
import 'package:get/get.dart';
import 'package:http/http.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher_string.dart';

class AnilistAuth extends GetxController {
Expand All @@ -35,6 +35,22 @@ class AnilistAuth extends GetxController {
RxList<TrackedMedia> currentlyReading = <TrackedMedia>[].obs;
RxList<TrackedMedia> mangaList = <TrackedMedia>[].obs;

void _handle403(http.Response response) {
dynamic errorJson;
try {
errorJson = jsonDecode(response.body);
} catch (_) {}

const base = "Why is it 403";
final apiMessage =
errorJson?['errors']?[0]?['message'] as String?;
final message = apiMessage != null && apiMessage.isNotEmpty
? "$base: $apiMessage"
: "$base: Forbidden (error 403)";

throw Exception(message);
}

Future<void> tryAutoLogin() async {
isLoggedIn.value = false;
final token = AuthKeys.authToken.get<String?>();
Expand All @@ -52,6 +68,25 @@ class AnilistAuth extends GetxController {
}
}

DateTime? getExpiryFromToken(String token) {
try {
final parts = token.split('.');
if (parts.length != 3) return null;

final payload = parts[1];
String normalizedSource = base64Url.normalize(payload);
final String decoded = utf8.decode(base64Url.decode(normalizedSource));
final Map<String, dynamic> map = json.decode(decoded);

if (map.containsKey('exp')) {
return DateTime.fromMillisecondsSinceEpoch(map['exp'] * 1000);
}
} catch (e) {
Logger.i('Error decoding token: $e');
}
return null;
}

Future<void> login(BuildContext context) async {
final selectedMethod = await showModalBottomSheet<String>(
context: context,
Expand All @@ -77,7 +112,7 @@ class AnilistAuth extends GetxController {
);
final code = Uri.parse(result).queryParameters['code'];
if (code != null) {
Logger.i("token found: $code");
Logger.i("token found");
await _exchangeCodeForToken(
code, clientId, clientSecret, redirectUri);
}
Expand Down Expand Up @@ -327,7 +362,7 @@ class AnilistAuth extends GetxController {

Future<void> _exchangeCodeForToken(String code, String clientId,
String clientSecret, String redirectUri) async {
final response = await post(
final response = await http.post(
Uri.parse('https://anilist.co/api/v2/oauth/token'),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Expand Down Expand Up @@ -371,6 +406,7 @@ class AnilistAuth extends GetxController {
Viewer {
id
name
about(asHtml: true)
avatar {
large
}
Expand All @@ -392,17 +428,47 @@ class AnilistAuth extends GetxController {
favourites {
anime {
pageInfo { total }
nodes {
id
title { userPreferred english romaji }
coverImage { large }
}
}
manga {
pageInfo { total }
nodes {
id
title { userPreferred english romaji }
coverImage { large }
}
}
characters {
nodes {
id
name { full }
image { large medium }
}
}
staff {
nodes {
id
name { full userPreferred }
image { large }
}
}
studios {
nodes {
id
name
}
}
}
}
}
''';

try {
final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand All @@ -417,6 +483,7 @@ class AnilistAuth extends GetxController {
final viewerData = data['data']['Viewer'];

final userProfile = Profile.fromJson(viewerData);
userProfile.tokenExpiry = getExpiryFromToken(token);
profileData.value = userProfile;
isLoggedIn.value = true;

Expand All @@ -425,6 +492,8 @@ class AnilistAuth extends GetxController {

// fetchFollowersAndFollowing(userProfile.id ?? '');
CommentsDatabase().login();
} else if (response.statusCode == 403) {
_handle403(response);
} else {
Logger.i('Failed to load user profile: ${response.statusCode}');
throw Exception('Failed to load user profile');
Expand Down Expand Up @@ -454,7 +523,7 @@ class AnilistAuth extends GetxController {
''';

try {
final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand All @@ -477,6 +546,8 @@ class AnilistAuth extends GetxController {
..following = followingCount;

profileData.value = updatedProfile;
} else if (response.statusCode == 403) {
_handle403(response);
} else {
Logger.i('Failed to load followers/following: ${response.statusCode}');
throw Exception('Failed to load followers/following ${response.body}');
Expand Down Expand Up @@ -540,7 +611,7 @@ class AnilistAuth extends GetxController {
throw Exception('Failed to get user ID');
}

final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand Down Expand Up @@ -585,6 +656,8 @@ class AnilistAuth extends GetxController {
} else {
Logger.i('Unexpected response structure: ${response.body}');
}
} else if (response.statusCode == 403) {
_handle403(response);
} else {
Logger.i('Fetch failed with status code: ${response.statusCode}');
Logger.i('Response body: ${response.body}');
Expand Down Expand Up @@ -619,7 +692,7 @@ class AnilistAuth extends GetxController {
throw Exception('Failed to get user ID');
}

final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand All @@ -643,6 +716,8 @@ class AnilistAuth extends GetxController {
} else {
fetchUserMangaList();
}
} else if (response.statusCode == 403) {
_handle403(response);
} else {
Logger.i('Failed to delete media with list ID $listId');
Logger.i('${response.statusCode}: ${response.body}');
Expand Down Expand Up @@ -701,7 +776,7 @@ class AnilistAuth extends GetxController {
variables['progress'] = progress;
}

final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand Down Expand Up @@ -735,6 +810,8 @@ class AnilistAuth extends GetxController {
fetchUserMangaList();
}
setCurrentMedia(listId, isManga: !isAnime);
} else if (response.statusCode == 403) {
_handle403(response);
} else {
Logger.i('Update failed with status code: ${response.statusCode}');
Logger.i('Response body: ${response.body}');
Expand Down Expand Up @@ -795,7 +872,7 @@ class AnilistAuth extends GetxController {
throw Exception('Failed to get user ID');
}

final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand Down Expand Up @@ -839,6 +916,8 @@ class AnilistAuth extends GetxController {
} else {
Logger.i('Unexpected response structure: ${response.body}');
}
} else if (response.statusCode == 403) {
_handle403(response);
} else {
Logger.i('Fetch failed with status code: ${response.statusCode}');
Logger.i('Response body: ${response.body}');
Expand Down Expand Up @@ -872,7 +951,7 @@ class AnilistAuth extends GetxController {
''';

try {
final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand All @@ -892,6 +971,8 @@ class AnilistAuth extends GetxController {

if (response.statusCode == 200) {
Logger.i('Anime status updated successfully: ${response.body}');
} else if (response.statusCode == 403) {
_handle403(response);
} else {
Logger.i('Failed to update anime status: ${response.statusCode}');
Logger.i('Response body: ${response.body}');
Expand Down Expand Up @@ -925,7 +1006,7 @@ class AnilistAuth extends GetxController {
''';

try {
final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand All @@ -945,6 +1026,8 @@ class AnilistAuth extends GetxController {

if (response.statusCode == 200) {
Logger.i('Manga status updated successfully: ${response.body}');
} else if (response.statusCode == 403) {
_handle403(response);
} else {
Logger.i('Failed to update manga status: ${response.statusCode}');
Logger.i('Response body: ${response.body}');
Expand All @@ -958,7 +1041,6 @@ class AnilistAuth extends GetxController {
final token = AuthKeys.authToken.get<String?>();
if (token == null) return false;


final String idField = type == "CHARACTER" ? "characterId" : "staffId";
final mutation = '''
mutation (\$id: Int) {
Expand All @@ -974,7 +1056,7 @@ class AnilistAuth extends GetxController {
''';

try {
final response = await post(
final response = await http.post(
Uri.parse('https://graphql.anilist.co'),
headers: {
'Authorization': 'Bearer $token',
Expand All @@ -986,7 +1068,12 @@ class AnilistAuth extends GetxController {
}),
);

return response.statusCode == 200;
if (response.statusCode == 200) {
return true;
} else if (response.statusCode == 403) {
_handle403(response);
}
return false;
} catch (e) {
Logger.i("Error toggling favorite: $e");
return false;
Expand Down
3 changes: 3 additions & 0 deletions lib/controllers/services/anilist/anilist_queries.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const detailsPrimaryQuery = '''
characters(sort: [ROLE, FAVOURITES_DESC], perPage: 25, page: 1) {
edges {
node {
id
name {
full
}
Expand All @@ -54,6 +55,8 @@ const detailsPrimaryQuery = '''
}
}
voiceActors(language: JAPANESE) {
id
languageV2
name {
full
}
Expand Down
Loading