mirror of
https://github.com/K3vinb5/Unyo.git
synced 2026-06-13 05:49:42 +00:00
rewrite: Refactor model imports and continue work on shikimori integration
This commit is contained in:
174
.agents/skills/fjson-dart-bean-generator/SKILL.md
Normal file
174
.agents/skills/fjson-dart-bean-generator/SKILL.md
Normal file
@@ -0,0 +1,174 @@
|
||||
---
|
||||
name: fjson-dart-bean-generator
|
||||
description: Generate Dart bean classes from JSON and regenerate serialization helpers using the fjson CLI. Use this skill whenever the user needs to create Dart models from API JSON responses, generate @JsonSerializable entity classes, or regenerate .g.dart helper files. Also use when the user mentions FlutterJsonBeanFactory, fjson, json_to_dart, JSON serialization, @JSONField, @JsonSerializable, or needs to add new API response DTOs to the unyo project.
|
||||
---
|
||||
|
||||
# fjson CLI — Dart Bean Generator
|
||||
|
||||
The fjson CLI generates `@JsonSerializable` Dart entity classes from JSON responses and regenerates `.g.dart` serialization helpers, `json_field.dart`, and `json_convert_content.dart`. It replaces the FlutterJsonBeanFactory IntelliJ plugin for CLI/agent workflows.
|
||||
|
||||
The bundled JAR lives inside this skill directory: **`fjson-cli.jar`**. Invoke it as:
|
||||
|
||||
```bash
|
||||
java -jar <path-to-skill>/fjson-cli.jar <command> [options]
|
||||
```
|
||||
|
||||
When running from the unyo project root, the skill is at `.agents/skills/fjson-dart-bean-generator/`:
|
||||
|
||||
```bash
|
||||
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar <command> [options]
|
||||
```
|
||||
|
||||
If you need to rebuild the JAR (rare — only after modifying fjson-cli source):
|
||||
|
||||
```bash
|
||||
cd ../fjson-cli && ./gradlew jar
|
||||
# Then copy the new JAR into the skill:
|
||||
cp ../fjson-cli/build/libs/fjson-cli.jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar
|
||||
```
|
||||
|
||||
## Two Commands
|
||||
|
||||
| Command | Purpose | When to use |
|
||||
|---------|---------|-------------|
|
||||
| `fjson bean` | Create a new entity `.dart` file from JSON | User provides a class name + JSON (string or file) |
|
||||
| `fjson gen` | Regenerate all `.g.dart` helpers, `json_field.dart`, `json_convert_content.dart` | After adding/modifying any `@JsonSerializable` class |
|
||||
|
||||
> **Important**: `fjson bean` **automatically runs** `fjson gen` when invoked inside a Flutter project (one with a `pubspec.yaml`). You do NOT need to run `gen` separately after `bean`.
|
||||
|
||||
## `fjson bean` — Generate a new entity from JSON
|
||||
|
||||
### Required flags
|
||||
|
||||
| Flag | Description | Example |
|
||||
|------|-------------|---------|
|
||||
| `--class <Name>` | Root class name (use the API response root name) | `--class MediaResponse` |
|
||||
| `--json <string>` | Raw JSON string | `--json '{"id":1,"title":"..."}'` |
|
||||
| `--file <path>` | Path to a `.json` file (alternative to `--json`) | `--file response.json` |
|
||||
|
||||
### Optional flags
|
||||
|
||||
| Flag | Description | Default | When to use |
|
||||
|------|-------------|---------|-------------|
|
||||
| `--output <path>` | Directory for the generated `.dart` file | `./lib` | Direct entity to correct DTO subfolder |
|
||||
| `--suffix <text>` | Suffix appended to generated class names | `entity` | Leave as default for unyo |
|
||||
| `--nullable` | Make fields nullable (`Type?`) | off | Rarely needed in unyo |
|
||||
| `--set-default` | Assign default values to primitive fields | off | **Always use this for unyo DTOs** |
|
||||
| `--project <path>` | Flutter project root | `.` | Usually not needed from unyo root |
|
||||
|
||||
### Typical unyo invocation
|
||||
|
||||
```bash
|
||||
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar bean \
|
||||
--class MediaCollectionResponse \
|
||||
--json '<paste JSON here>' \
|
||||
--output ./lib/core/services/api/dto/anilist/ \
|
||||
--set-default
|
||||
```
|
||||
|
||||
Or from a file:
|
||||
|
||||
```bash
|
||||
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar bean \
|
||||
--class AnizipEpisodeInfo \
|
||||
--file ./response.json \
|
||||
--output ./lib/core/services/api/dto/anizip/ \
|
||||
--set-default
|
||||
```
|
||||
|
||||
### What gets generated
|
||||
|
||||
The command produces a `.dart` file containing:
|
||||
|
||||
- A root `@JsonSerializable()` class with `--suffix` appended (e.g., `MediaCollectionResponse` → `MediaCollectionResponseEntity`)
|
||||
- Nested `@JsonSerializable()` classes for each nested JSON object (e.g., `MediaCollectionResponseDtoPage`)
|
||||
- `@JSONField(name: 'original_key')` annotations for keys whose Dart naming differs from JSON
|
||||
- `late` fields with default values (if `--set-default`)
|
||||
- `fromJson()` factory and `toJson()` method stubs
|
||||
- `import` of `json_field.dart` and the matching `.g.dart`
|
||||
- `export` of the matching `.g.dart`
|
||||
|
||||
The generated entity **also auto-triggers `fjson gen`**, so the matching `.g.dart`, `json_field.dart`, and `json_convert_content.dart` are all regenerated immediately.
|
||||
|
||||
## `fjson gen` — Regenerate all helpers
|
||||
|
||||
```bash
|
||||
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar gen --project .
|
||||
```
|
||||
|
||||
This scans `lib/**/*.dart` for every `@JsonSerializable` class and:
|
||||
|
||||
1. Regenerates each `<entity>.g.dart` file in `lib/generated/json/`
|
||||
2. Rebuilds `lib/generated/json/base/json_field.dart` (annotation definitions)
|
||||
3. Rebuilds `lib/generated/json/base/json_convert_content.dart` (the `JsonConvert` runtime and `JsonConvertClassCollection` registry with all entity imports)
|
||||
4. Deletes any stale `.g.dart` files for entities that no longer exist
|
||||
|
||||
Run this **after any manual edit** to an entity file (adding/removing/renaming fields).
|
||||
|
||||
## Generated File Layout in unyo
|
||||
|
||||
```
|
||||
unyo/
|
||||
├── lib/core/services/api/dto/
|
||||
│ └── anilist/
|
||||
│ └── media_response_entity.dart ← fjson bean output
|
||||
└── lib/generated/json/
|
||||
├── media_response_entity.g.dart ← auto-generated helpers
|
||||
├── media_collection_graphql_entity.g.dart ← existing
|
||||
├── ... ← all other .g.dart
|
||||
└── base/
|
||||
├── json_field.dart ← annotations
|
||||
└── json_convert_content.dart ← registry + runtime
|
||||
```
|
||||
|
||||
### Entity file naming convention in unyo
|
||||
|
||||
- **Snake_case filenames**: e.g., `media_details_graphql_entity.dart`
|
||||
- **PascalCase class names**: e.g., `MediaDetailsGraphqlEntity`
|
||||
- fjson converts PascalCase `--class` names to snake_case filenames automatically
|
||||
- Always place entities in the correct DTO subfolder: `lib/core/services/api/dto/<provider>/`
|
||||
- Providers: `anilist/`, `anizip/`, `aniskip/`, `extensions/`
|
||||
|
||||
### Default unyo settings that fjson matches
|
||||
|
||||
- `--set-default` is always used → all fields get `= ''`, `= 0`, `= false`, etc.
|
||||
- `--suffix entity` (default) → class names end with `Entity`
|
||||
- `flutter_json.generated_path` is `generated/json` in `pubspec.yaml`
|
||||
|
||||
## Workflow: Adding a new API response model
|
||||
|
||||
1. **Get the JSON** — Either from the user, from a file, or from a GraphQL response
|
||||
2. **Determine the provider** (anilist, anizip, aniskip, extensions)
|
||||
3. **Run `fjson bean`** with `--class`, `--json/--file`, `--output`, and `--set-default`:
|
||||
```bash
|
||||
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar bean \
|
||||
--class NewApiResponse \
|
||||
--json '<the JSON>' \
|
||||
--output ./lib/core/services/api/dto/anilist/ \
|
||||
--set-default
|
||||
```
|
||||
4. **Verify the output** — Open the generated `.dart` file and check:
|
||||
- Class names and field types are correct
|
||||
- Nested objects are properly generated as sub-classes
|
||||
- `@JSONField(name: ...)` mappings are correct for non-matching keys
|
||||
5. **Update `json_convert_content.dart`** — Already done automatically by `fjson gen` (triggered by `fjson bean`). Verify the new entity's import is present.
|
||||
6. **Run analysis** — `flutter analyze` to ensure no issues
|
||||
7. **If fields need adjustment** — Edit the entity file directly, then re-run `fjson gen`:
|
||||
```bash
|
||||
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar gen --project .
|
||||
```
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- **Wrong `--output` path**: Entity files must go to the correct provider subfolder (`lib/core/services/api/dto/<provider>/`) for the import in `json_convert_content.dart` and `.g.dart` files to resolve correctly.
|
||||
- **Forgetting `--set-default`**: Without it, fields use `late` without defaults. In unyo, all DTO fields have defaults (except `dynamic`).
|
||||
- **Running in wrong directory**: Commands assume the current working directory is the unyo project root (where `pubspec.yaml` lives). The `--project` flag overrides this.
|
||||
- **Class name collision**: If a class name already exists in another entity file, the generated `.g.dart` will have duplicate function names, causing compile errors. Check for existing names before running.
|
||||
- **JSON with empty arrays**: fjson handles this but cannot infer the element type of an empty `List`. The field will be typed `List<dynamic>` and must be corrected manually.
|
||||
- **After running `bean` in a non-Flutter directory**: `fjson gen` is skipped. You must manually run it from the project root.
|
||||
|
||||
## Cross-references
|
||||
|
||||
- **unyo project structure and entity patterns**: See `unyo-domain-data-layer` skill
|
||||
- **DTO conventions and GraphQL response mapping**: See `unyo-domain-data-layer` skill
|
||||
- **Rebuilding fjson-cli from source**: See `../fjson-cli/README.md`
|
||||
BIN
.agents/skills/fjson-dart-bean-generator/fjson-cli.jar
Normal file
BIN
.agents/skills/fjson-dart-bean-generator/fjson-cli.jar
Normal file
Binary file not shown.
@@ -27,8 +27,8 @@ import 'package:unyo/core/notification/reload/reload_type.dart';
|
||||
import 'package:unyo/core/notification/user_notifier.dart';
|
||||
import 'package:unyo/core/notification/video_info_notifier.dart';
|
||||
import 'package:unyo/core/services/api/http/http_exception.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/local_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/user/local_user_model.dart';
|
||||
import 'package:unyo/domain/repositories/anime_repository.dart';
|
||||
import 'package:unyo/domain/repositories/episode_repository.dart';
|
||||
import 'package:unyo/data/repositories/extension_repository_aniyomi.dart';
|
||||
|
||||
@@ -21,8 +21,8 @@ import 'package:unyo/core/notification/reload/reload_notifier.dart';
|
||||
import 'package:unyo/core/notification/reload/reload_type.dart';
|
||||
import 'package:unyo/core/notification/user_notifier.dart';
|
||||
import 'package:unyo/application/effects/app_effects.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/local_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/user/local_user_model.dart';
|
||||
import 'package:unyo/domain/repositories/anime_repository.dart';
|
||||
import 'package:unyo/data/repositories/repositories.dart';
|
||||
import 'package:unyo/domain/entities/media/anime.dart';
|
||||
|
||||
@@ -17,8 +17,8 @@ import 'package:unyo/core/notification/manga_notifier.dart';
|
||||
import 'package:unyo/core/notification/media_list_notifier.dart';
|
||||
import 'package:unyo/core/notification/user_notifier.dart';
|
||||
import 'package:unyo/core/services/api/http/http_exception.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/local_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/user/local_user_model.dart';
|
||||
import 'package:unyo/data/repositories/extension_repository_aniyomi.dart';
|
||||
import 'package:unyo/domain/repositories/manga_repository.dart';
|
||||
import 'package:unyo/data/repositories/repositories.dart';
|
||||
|
||||
@@ -11,8 +11,8 @@ import 'package:unyo/core/notification/anime_notifier.dart';
|
||||
import 'package:unyo/core/notification/manga_notifier.dart';
|
||||
import 'package:unyo/core/notification/media_list_notifier.dart';
|
||||
import 'package:unyo/core/notification/user_notifier.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/local_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/user/local_user_model.dart';
|
||||
import 'package:unyo/data/repositories/user_repository_anilist.dart';
|
||||
import 'package:unyo/domain/entities/media/anime.dart';
|
||||
import 'package:unyo/domain/entities/media/manga.dart';
|
||||
|
||||
@@ -18,8 +18,8 @@ import 'package:unyo/core/services/media/episode_service.dart';
|
||||
import 'package:unyo/core/services/media/media_service.dart';
|
||||
import 'package:unyo/core/theme/color_image_service.dart';
|
||||
import 'package:unyo/core/theme/theme_service.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/local_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/user/local_user_model.dart';
|
||||
import 'package:unyo/data/repositories/repositories.dart';
|
||||
import 'package:unyo/domain/entities/user/settings.dart';
|
||||
import 'package:unyo/domain/entities/user/user.dart';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Application configuration
|
||||
const String version = 'v1.0.0';
|
||||
// Locator configuration
|
||||
const String applicationSupportDirectory = "applicationSupportDirectory";
|
||||
const String anilistGraphQlService = 'anilistGraphQlService';
|
||||
const String loggedUserNotifier = 'loggedUserNotifier';
|
||||
const String newUserNotifier = 'newUserNotifier';
|
||||
// Anilist API configuration
|
||||
@@ -11,15 +11,19 @@ const String anilistAuthUrl =
|
||||
const String anilistRedirectUri = 'http://localhost:9999/auth';
|
||||
const String anilistClientId = '17550';
|
||||
const String anilistClientSecret = 'xI8KTZlKm2F3kHXLko1ArQ21bKap4MojgDTk6Ukx';
|
||||
const String anilistGraphQlService = 'anilistGraphQlService';
|
||||
const String anilistGraphQLEndpoint = 'https://graphql.anilist.co';
|
||||
// Shikimori API configuration
|
||||
const String shikimoriGraphQlService = 'shikimoriGraphQlService';
|
||||
const String shikimoriGraphQLEndpoint = 'https://shikimori.io/api/graphql';
|
||||
// Anizip API configuration
|
||||
const String anizipBaseEndpoint = 'https://api.ani.zip';
|
||||
// Aniski API configuration
|
||||
const String aniskiBaseEndpoint = 'https://api.aniskip.com';
|
||||
// Torrent API configuration
|
||||
const String torrentServiceEndpoint = 'http://127.0.0.1:8090';
|
||||
const String localhost = '127.0.0.1';
|
||||
// Cache configuration
|
||||
const String localhost = '127.0.0.1';
|
||||
const Set<String> cacheDisabledEndpoints = <String>{
|
||||
anilistOAuthEndpoint,
|
||||
};
|
||||
@@ -30,7 +34,7 @@ const Set<String> cacheIgnoredHeaders = <String>{
|
||||
'Authorization'
|
||||
};
|
||||
// Extensions condiguration
|
||||
const String aniyomiExtensionsRepositoryUrl = 'https://gitea.k3vinb5.dev/Backups/kohi-den-extensions/raw/branch/main/index.min.json';
|
||||
const String tachiyomiExtensionsRepositoryUrl = 'https://gitea.k3vinb5.dev/Backups/keiyoushi-extensions/raw/branch/repo/index.min.json';
|
||||
const String aniyomiExtensionsDefaultRepositoryUrl = 'https://gitea.k3vinb5.dev/Backups/kohi-den-extensions/raw/branch/main/index.min.json';
|
||||
const String tachiyomiExtensionsDefaultRepositoryUrl = 'https://gitea.k3vinb5.dev/Backups/keiyoushi-extensions/raw/branch/repo/index.min.json';
|
||||
// TODO move to an asset
|
||||
const plusImageUrl = "https://i.ibb.co/Kj8CQZH/cross.png";
|
||||
@@ -70,6 +70,10 @@ void setupLocator() async{
|
||||
() => GraphQLService(httpService: sl<HttpService>(), endpoint: config.anilistGraphQLEndpoint),
|
||||
instanceName: config.anilistGraphQlService,
|
||||
);
|
||||
sl.registerLazySingleton<GraphQLService>(
|
||||
() => GraphQLService(httpService: sl<HttpService>(), endpoint: config.shikimoriGraphQLEndpoint),
|
||||
instanceName: config.shikimoriGraphQlService,
|
||||
);
|
||||
sl.registerLazySingleton<AppEffectHandler>(() => AppEffectHandler());
|
||||
sl.registerLazySingleton<ColorImageService>(() => ColorImageService());
|
||||
sl.registerSingleton<AniyomiBridge>(AniyomiBridge());
|
||||
@@ -104,6 +108,8 @@ void setupLocator() async{
|
||||
));
|
||||
sl.registerLazySingleton<AnimeRepositoryAnilist>(() => AnimeRepositoryAnilist());
|
||||
sl.registerLazySingleton<MangaRepositoryAnilist>(() => MangaRepositoryAnilist());
|
||||
sl.registerLazySingleton<AnimeRepositoryShikimori>(() => AnimeRepositoryShikimori());
|
||||
sl.registerLazySingleton<MangaRepositoryShikimori>(() => MangaRepositoryShikimori());
|
||||
sl.registerLazySingleton<AnimeRepository>(() => AnimeRepositoryFactory());
|
||||
sl.registerLazySingleton<MangaRepository>(() => MangaRepositoryFactory());
|
||||
sl.registerLazySingleton<EpisodeRepositoryAnizip>(() => EpisodeRepositoryAnizip());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// { }
|
||||
const viewerQuery = '''
|
||||
const viewerQuery =
|
||||
'''
|
||||
query Viewer {
|
||||
Viewer {
|
||||
id
|
||||
@@ -25,7 +26,8 @@ query Viewer {
|
||||
// "userId": 0,
|
||||
// "type" : "ANIME" or "MANGA"
|
||||
// }
|
||||
const mediaListCollectionQuery = '''
|
||||
const mediaListCollectionQuery =
|
||||
'''
|
||||
query MediaListCollection(\$userName: String, \$userId: Int, \$type: MediaType) {
|
||||
MediaListCollection(userName: \$userName, userId: \$userId, type: \$type) {
|
||||
lists {
|
||||
@@ -145,7 +147,8 @@ query Page(\$sort: [AiringSort], \$page: Int, \$perPage: Int, \$notYetAired: Boo
|
||||
// "sort": "POPULARITY_DESC" or "TRENDING_DESC",
|
||||
// "type": "ANIME" or "MANGA"
|
||||
// }
|
||||
const mediaTrendingOrPopularQuery = '''
|
||||
const mediaTrendingOrPopularQuery =
|
||||
'''
|
||||
query Page(\$page: Int, \$perPage: Int, \$sort: [MediaSort], \$type: MediaType) {
|
||||
Page(page: \$page, perPage: \$perPage) {
|
||||
media(sort: \$sort, type: \$type) {
|
||||
@@ -192,7 +195,6 @@ query Page(\$page: Int, \$perPage: Int, \$sort: [MediaSort], \$type: MediaType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
''';
|
||||
// {
|
||||
// "page" : 1,
|
||||
@@ -202,7 +204,8 @@ query Page(\$page: Int, \$perPage: Int, \$sort: [MediaSort], \$type: MediaType)
|
||||
// "endDateGreater": 20250612,
|
||||
// "endDateLesser": 20250712
|
||||
// }
|
||||
const mediaRecentlyCompletedQuery = '''
|
||||
const mediaRecentlyCompletedQuery =
|
||||
'''
|
||||
query Page(\$page: Int, \$perPage: Int, \$sort: [MediaSort], \$type: MediaType, \$endDateGreater: FuzzyDateInt, \$endDateLesser: FuzzyDateInt) {
|
||||
Page(page: \$page, perPage: \$perPage) {
|
||||
media(sort: \$sort, type: \$type, endDate_greater: \$endDateGreater, endDate_lesser: \$endDateLesser) {
|
||||
@@ -257,7 +260,8 @@ query Page(\$page: Int, \$perPage: Int, \$sort: [MediaSort], \$type: MediaType,
|
||||
// "sort": "POPULARITY_DESC" or "TRENDING_DESC",
|
||||
// "startDateGreater": 20250724
|
||||
// }
|
||||
const mediaUpcomingQuery = '''
|
||||
const mediaUpcomingQuery =
|
||||
'''
|
||||
query Page(\$page: Int, \$perPage: Int, \$sort: [MediaSort], \$type: MediaType, \$startDateGreater: FuzzyDateInt) {
|
||||
Page(page: \$page, perPage: \$perPage) {
|
||||
media(sort: \$sort, type: \$type, startDate_greater: \$startDateGreater) {
|
||||
@@ -312,7 +316,8 @@ query Page(\$page: Int, \$perPage: Int, \$sort: [MediaSort], \$type: MediaType,
|
||||
// "airingAtGreater": 1700000000, milliseconds since epoch
|
||||
// "airingAtLesser": 1800000000, milliseconds since epoch
|
||||
// }
|
||||
const calendarQuery = '''
|
||||
const calendarQuery =
|
||||
'''
|
||||
query Page(\$sort: [AiringSort], \$page: Int, \$perPage: Int, \$airingAtGreater: Int, \$airingAtLesser: Int) {
|
||||
Page(page: \$page, perPage: \$perPage) {
|
||||
airingSchedules(sort: \$sort, airingAt_greater: \$airingAtGreater, airingAt_lesser: \$airingAtLesser) {
|
||||
@@ -368,7 +373,9 @@ query Page(\$sort: [AiringSort], \$page: Int, \$perPage: Int, \$airingAtGreater:
|
||||
// "page" : 1,
|
||||
// "perPage": 20,
|
||||
// }
|
||||
const mediaDetailsQuery = '''query Page(\$type: MediaType, \$mediaId: Int, \$page: Int, \$perPage: Int) {
|
||||
const mediaDetailsQuery =
|
||||
'''
|
||||
query Page(\$type: MediaType, \$mediaId: Int, \$page: Int, \$perPage: Int) {
|
||||
Media(id: \$mediaId, type: \$type) {
|
||||
id
|
||||
title {
|
||||
@@ -463,7 +470,9 @@ const mediaDetailsQuery = '''query Page(\$type: MediaType, \$mediaId: Int, \$pag
|
||||
// {
|
||||
// "mediaId": selectedAnime.id
|
||||
// }
|
||||
const mediaListEntryQuery = '''query Page(\$mediaId: Int) {
|
||||
const mediaListEntryQuery =
|
||||
'''
|
||||
query Page(\$mediaId: Int) {
|
||||
Media(id: \$mediaId) {
|
||||
mediaListEntry {
|
||||
progress
|
||||
@@ -495,7 +504,8 @@ const mediaListEntryQuery = '''query Page(\$mediaId: Int) {
|
||||
// "genres": ["Action", "Fantasy"],
|
||||
// "sort": "POPULARITY_DESC"
|
||||
// }
|
||||
const mediaAdvancedSearchQuery = '''
|
||||
const mediaAdvancedSearchQuery =
|
||||
'''
|
||||
query (
|
||||
\$page: Int, \$perPage: Int, \$type: MediaType, \$season: MediaSeason, \$seasonYear: Int, \$format: MediaFormat, \$status: MediaStatus, \$genres: [String], \$sort: [MediaSort], \$search: String, \$countryOfOrigin: CountryCode
|
||||
) {
|
||||
@@ -503,7 +513,7 @@ query (
|
||||
media(
|
||||
type: \$type, season: \$season, seasonYear: \$seasonYear, format: \$format, status: \$status, genre_in: \$genres, sort: \$sort, search: \$search, countryOfOrigin: \$countryOfOrigin
|
||||
) {
|
||||
id
|
||||
id
|
||||
idMal
|
||||
title {
|
||||
english
|
||||
@@ -557,7 +567,8 @@ id
|
||||
// "completedAt": {"day": 1, "month": 2, "year": 2023},
|
||||
// "status": "COMPLETED"
|
||||
// }
|
||||
const updateMediaEntryQuery = '''
|
||||
const updateMediaEntryQuery =
|
||||
'''
|
||||
mutation SaveMediaListEntry(\$mediaId: Int, \$progress: Int, \$progressVolumes: Int, \$repeat: Int, \$score: Float, \$startedAt: FuzzyDateInput, \$completedAt: FuzzyDateInput, \$status: MediaListStatus) {
|
||||
SaveMediaListEntry(mediaId: \$mediaId, progress: \$progress, progressVolumes: \$progressVolumes, repeat: \$repeat, score: \$score, startedAt: \$startedAt, completedAt: \$completedAt, status: \$status) {
|
||||
progress
|
||||
|
||||
@@ -0,0 +1,410 @@
|
||||
//sort and type are important
|
||||
// {
|
||||
// "page": 1,
|
||||
// "limit": 50,
|
||||
// "order": "aired_on" or "popularity",
|
||||
// }
|
||||
const animeUpcomingOrPopularQuery =
|
||||
'''
|
||||
query Animes(\$page: PositiveInt, \$limit: PositiveInt, \$order: OrderEnum) {
|
||||
animes(page: \$page, limit: \$limit, order: \$order) {
|
||||
malId
|
||||
id
|
||||
english
|
||||
name
|
||||
russian
|
||||
japanese
|
||||
poster {
|
||||
originalUrl
|
||||
mainAlt2xUrl
|
||||
}
|
||||
description
|
||||
duration
|
||||
airedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
releasedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
episodes
|
||||
nextEpisodeAt
|
||||
genres {
|
||||
kind
|
||||
name
|
||||
}
|
||||
kind
|
||||
isCensored
|
||||
score
|
||||
season
|
||||
status
|
||||
}
|
||||
}
|
||||
''';
|
||||
// {
|
||||
// "page": 1,
|
||||
// "limit": 50,
|
||||
// "season": "sprint_2026"
|
||||
// "order": "popularity",
|
||||
// }
|
||||
const animeTrendingQuery =
|
||||
'''
|
||||
query Animes(\$page: PositiveInt, \$limit: PositiveInt, \$order: OrderEnum, \$season: SeasonString) {
|
||||
animes(page: \$page, limit: \$limit, order: \$order, season: \$season) {
|
||||
malId
|
||||
id
|
||||
english
|
||||
name
|
||||
russian
|
||||
japanese
|
||||
poster {
|
||||
originalUrl
|
||||
mainAlt2xUrl
|
||||
}
|
||||
description
|
||||
duration
|
||||
airedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
releasedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
episodes
|
||||
nextEpisodeAt
|
||||
genres {
|
||||
kind
|
||||
name
|
||||
}
|
||||
kind
|
||||
isCensored
|
||||
score
|
||||
season
|
||||
status
|
||||
}
|
||||
}
|
||||
''';
|
||||
// {
|
||||
// "page": 1,
|
||||
// "limit": 50,
|
||||
// "season": "sprint_2026"
|
||||
// "order": "updated_at" or "popularity",
|
||||
// "status": "ongoing" or "released"
|
||||
// }
|
||||
const animeRecentlyReleasedOrRecentlyCompletedQuery =
|
||||
'''
|
||||
query Animes(\$page: PositiveInt, \$limit: PositiveInt, \$order: OrderEnum, \$season: SeasonString, \$status: AnimeStatusString) {
|
||||
animes(page: \$page, limit: \$limit, order: \$order, season: \$season, status: \$status) {
|
||||
malId
|
||||
id
|
||||
english
|
||||
name
|
||||
russian
|
||||
japanese
|
||||
poster {
|
||||
originalUrl
|
||||
mainAlt2xUrl
|
||||
}
|
||||
description
|
||||
duration
|
||||
airedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
releasedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
episodes
|
||||
nextEpisodeAt
|
||||
genres {
|
||||
kind
|
||||
name
|
||||
}
|
||||
kind
|
||||
isCensored
|
||||
score
|
||||
season
|
||||
status
|
||||
}
|
||||
}
|
||||
''';
|
||||
// {
|
||||
// "ids": selectedAnime.id,
|
||||
// "page" : 1,
|
||||
// "limit": 20,
|
||||
// }
|
||||
const String shikimoriAnimeDetailsQuery = '''
|
||||
query Animes(\$ids: String, \$page: PositiveInt, \$limit: PositiveInt) {
|
||||
animes(ids: \$ids, page: \$page, limit: \$limit) {
|
||||
userRate {
|
||||
episodes
|
||||
score
|
||||
rewatches
|
||||
status
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
characterRoles {
|
||||
character {
|
||||
id
|
||||
poster {
|
||||
originalUrl
|
||||
}
|
||||
name
|
||||
}
|
||||
}
|
||||
related {
|
||||
relationKind
|
||||
anime {
|
||||
malId
|
||||
id
|
||||
english
|
||||
name
|
||||
russian
|
||||
japanese
|
||||
poster {
|
||||
originalUrl
|
||||
mainAlt2xUrl
|
||||
}
|
||||
description
|
||||
duration
|
||||
airedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
releasedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
episodes
|
||||
nextEpisodeAt
|
||||
genres {
|
||||
kind
|
||||
name
|
||||
}
|
||||
kind
|
||||
isCensored
|
||||
score
|
||||
season
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
''';
|
||||
// {
|
||||
// "page": 1,
|
||||
// "limit": 50,
|
||||
// "order": "aired_on" or "popularity",
|
||||
// }
|
||||
const mangaUpcomingOrPopularQuery =
|
||||
'''
|
||||
query Mangas(\$page: PositiveInt, \$limit: PositiveInt, \$order: OrderEnum) {
|
||||
mangas(page: \$page, limit: \$limit, order: \$order) {
|
||||
malId
|
||||
id
|
||||
english
|
||||
name
|
||||
russian
|
||||
japanese
|
||||
poster {
|
||||
originalUrl
|
||||
mainAlt2xUrl
|
||||
}
|
||||
description
|
||||
airedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
releasedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
chapters
|
||||
genres {
|
||||
kind
|
||||
name
|
||||
}
|
||||
kind
|
||||
isCensored
|
||||
score
|
||||
status
|
||||
}
|
||||
}
|
||||
''';
|
||||
// {
|
||||
// "page": 1,
|
||||
// "limit": 50,
|
||||
// "season": "sprint_2026"
|
||||
// "order": "popularity",
|
||||
// }
|
||||
const mangaTrendingQuery =
|
||||
'''
|
||||
query Mangas(\$page: PositiveInt, \$limit: PositiveInt, \$order: OrderEnum, \$season: SeasonString) {
|
||||
mangas(page: \$page, limit: \$limit, order: \$order, season: \$season) {
|
||||
malId
|
||||
id
|
||||
english
|
||||
name
|
||||
russian
|
||||
japanese
|
||||
poster {
|
||||
originalUrl
|
||||
mainAlt2xUrl
|
||||
}
|
||||
description
|
||||
airedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
releasedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
chapters
|
||||
genres {
|
||||
kind
|
||||
name
|
||||
}
|
||||
kind
|
||||
isCensored
|
||||
score
|
||||
status
|
||||
}
|
||||
}
|
||||
''';
|
||||
// {
|
||||
// "page": 1,
|
||||
// "limit": 50,
|
||||
// "season": "sprint_2026"
|
||||
// "order": "updated_at" or "popularity",
|
||||
// "status": "ongoing" or "released"
|
||||
// }
|
||||
const mangaRecentlyReleasedOrRecentlyCompletedQuery =
|
||||
'''
|
||||
query Mangas(\$page: PositiveInt, \$limit: PositiveInt, \$order: OrderEnum, \$season: SeasonString, \$status: MangaStatusString) {
|
||||
mangas(page: \$page, limit: \$limit, order: \$order, season: \$season, status: \$status) {
|
||||
malId
|
||||
id
|
||||
english
|
||||
name
|
||||
russian
|
||||
japanese
|
||||
poster {
|
||||
originalUrl
|
||||
mainAlt2xUrl
|
||||
}
|
||||
description
|
||||
airedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
releasedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
chapters
|
||||
genres {
|
||||
kind
|
||||
name
|
||||
}
|
||||
kind
|
||||
isCensored
|
||||
score
|
||||
status
|
||||
}
|
||||
}
|
||||
''';
|
||||
// {
|
||||
// "ids": selectedManga.id,
|
||||
// "page" : 1,
|
||||
// "limit": 20,
|
||||
// }
|
||||
const String shikimoriMangaDetailsQuery =
|
||||
'''
|
||||
query Mangas(\$ids: String, \$page: PositiveInt, \$limit: PositiveInt) {
|
||||
mangas(ids: \$ids, page: \$page, limit: \$limit) {
|
||||
userRate {
|
||||
episodes
|
||||
score
|
||||
rewatches
|
||||
status
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
characterRoles {
|
||||
character {
|
||||
id
|
||||
poster {
|
||||
originalUrl
|
||||
}
|
||||
name
|
||||
}
|
||||
}
|
||||
related {
|
||||
relationKind
|
||||
manga {
|
||||
malId
|
||||
id
|
||||
english
|
||||
name
|
||||
russian
|
||||
japanese
|
||||
poster {
|
||||
originalUrl
|
||||
mainAlt2xUrl
|
||||
}
|
||||
description
|
||||
airedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
releasedOn {
|
||||
day
|
||||
month
|
||||
year
|
||||
}
|
||||
chapters
|
||||
genres {
|
||||
kind
|
||||
name
|
||||
}
|
||||
kind
|
||||
isCensored
|
||||
score
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
''';
|
||||
// Genres list query
|
||||
const String shikimoriGenresListQuery =
|
||||
r'''
|
||||
query GenresList($entryType: GenreEntryTypeEnum!) {
|
||||
genres(entryType: $entryType) {
|
||||
id
|
||||
name
|
||||
russian
|
||||
kind
|
||||
}
|
||||
}
|
||||
''';
|
||||
|
||||
@@ -73,7 +73,7 @@ class ShikimoriMediaService extends MediaService {
|
||||
Service get service => Service.shikimori;
|
||||
|
||||
@override
|
||||
List<String> get titleLanguages => [];
|
||||
List<String> get titleLanguages => ['Romaji', 'English', 'Native', 'Russian'];
|
||||
}
|
||||
|
||||
class SimklMediaService extends MediaService {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/local_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/user/local_user_model.dart';
|
||||
import 'package:unyo/data/repositories/user_repository_anilist.dart';
|
||||
import 'package:unyo/data/repositories/user_repository_local.dart';
|
||||
import 'package:unyo/domain/entities/user/settings.dart';
|
||||
|
||||
@@ -4,8 +4,8 @@ import 'package:unyo/core/services/api/dto/anilist/media_details_graphql_entity.
|
||||
import 'package:unyo/core/services/api/dto/anilist/media_details_media_list_entry_entity.dart';
|
||||
import 'package:unyo/data/adapters/adapters_names.dart' as names;
|
||||
import 'package:unyo/data/adapters/adapters_types.dart' as types;
|
||||
import 'package:unyo/data/models/anilist/anilist_anime_model.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_media_character.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_anime_model.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_media_character.dart';
|
||||
import 'package:unyo/domain/entities/media/anime.dart';
|
||||
import 'package:unyo/domain/entities/media/anime_details.dart';
|
||||
import 'package:unyo/domain/entities/media/media_character.dart';
|
||||
@@ -4,8 +4,8 @@ import 'package:unyo/core/services/api/dto/anilist/media_details_graphql_entity.
|
||||
import 'package:unyo/core/services/api/dto/anilist/media_details_media_list_entry_entity.dart';
|
||||
import 'package:unyo/data/adapters/adapters_names.dart' as names;
|
||||
import 'package:unyo/data/adapters/adapters_types.dart' as types;
|
||||
import 'package:unyo/data/models/anilist/anilist_manga_model.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_media_character.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_manga_model.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_media_character.dart';
|
||||
import 'package:unyo/domain/entities/media/manga.dart';
|
||||
import 'package:unyo/domain/entities/media/manga_details.dart';
|
||||
import 'package:unyo/domain/entities/media/media_character.dart';
|
||||
@@ -1,7 +1,7 @@
|
||||
export 'anilist/anilist_anime_details.dart';
|
||||
export 'anilist/anilist_anime_model.dart';
|
||||
export 'anilist/anilist_manga_details.dart';
|
||||
export 'anilist/anilist_manga_model.dart';
|
||||
export 'anilist/anilist_media_character.dart';
|
||||
export 'anilist/anilist_user_model.dart';
|
||||
export 'local/local_user_model.dart';
|
||||
export 'anilist/media/anilist_anime_details.dart';
|
||||
export 'anilist/media/anilist_anime_model.dart';
|
||||
export 'anilist/media/anilist_manga_details.dart';
|
||||
export 'anilist/media/anilist_manga_model.dart';
|
||||
export 'anilist/media/anilist_media_character.dart';
|
||||
export 'anilist/user/anilist_user_model.dart';
|
||||
export 'local/user/local_user_model.dart';
|
||||
|
||||
55
lib/data/models/shikimori/media/shikimori_anime_details.dart
Normal file
55
lib/data/models/shikimori/media/shikimori_anime_details.dart
Normal file
@@ -0,0 +1,55 @@
|
||||
// External dependencies
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
// Internal dependencies
|
||||
import 'package:unyo/domain/entities/list/media_list_entry.dart';
|
||||
import 'package:unyo/domain/entities/media/anime.dart';
|
||||
import 'package:unyo/domain/entities/media/anime_details.dart';
|
||||
import 'package:unyo/domain/entities/media/media_character.dart';
|
||||
|
||||
part 'shikimori_anime_details.freezed.dart';
|
||||
part 'shikimori_anime_details.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ShikimoriAnimeDetailsModel
|
||||
with _$ShikimoriAnimeDetailsModel
|
||||
implements AnimeDetails {
|
||||
const factory ShikimoriAnimeDetailsModel({
|
||||
@MediaListEntryConverter() required MediaListEntry mediaListEntry,
|
||||
@AnimeConverter() required List<Anime> recommendedAnimes,
|
||||
@MediaCharacterConverter() required List<MediaCharacter> characters,
|
||||
}) = _ShikimoriAnimeDetailsModel;
|
||||
|
||||
factory ShikimoriAnimeDetailsModel.empty() => ShikimoriAnimeDetailsModel(
|
||||
mediaListEntry: MediaListEntryModel.empty(),
|
||||
recommendedAnimes: [],
|
||||
characters: [],
|
||||
);
|
||||
|
||||
factory ShikimoriAnimeDetailsModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$ShikimoriAnimeDetailsModelFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$ShikimoriAnimeDetailsModelToJson(this as _ShikimoriAnimeDetailsModel);
|
||||
|
||||
// factory ShikimoriAnimeDetailsModel.fromDetailsEntry(
|
||||
// ShikimoriAnimeDetailsGraphqlAnime entry,) {
|
||||
// final recommendedAnimes = <Anime>[];
|
||||
// for (final related in entry.related) {
|
||||
// recommendedAnimes.add(
|
||||
// ShikimoriAnimeModel.fromRelatedEntry(related.anime),
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// final characters = entry.characterRoles
|
||||
// .map((role) => ShikimoriMediaCharacterModel.fromCharacterRole(role))
|
||||
// .toList();
|
||||
//
|
||||
// return ShikimoriAnimeDetailsModel(
|
||||
// mediaListEntry: MediaListEntryModel.empty(),
|
||||
// recommendedAnimes: recommendedAnimes,
|
||||
// characters: characters,
|
||||
// );
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'shikimori_anime_details.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ShikimoriAnimeDetailsModel {
|
||||
|
||||
@MediaListEntryConverter() MediaListEntry get mediaListEntry;@AnimeConverter() List<Anime> get recommendedAnimes;@MediaCharacterConverter() List<MediaCharacter> get characters;
|
||||
/// Create a copy of ShikimoriAnimeDetailsModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ShikimoriAnimeDetailsModelCopyWith<ShikimoriAnimeDetailsModel> get copyWith => _$ShikimoriAnimeDetailsModelCopyWithImpl<ShikimoriAnimeDetailsModel>(this as ShikimoriAnimeDetailsModel, _$identity);
|
||||
|
||||
/// Serializes this ShikimoriAnimeDetailsModel to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ShikimoriAnimeDetailsModel&&(identical(other.mediaListEntry, mediaListEntry) || other.mediaListEntry == mediaListEntry)&&const DeepCollectionEquality().equals(other.recommendedAnimes, recommendedAnimes)&&const DeepCollectionEquality().equals(other.characters, characters));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,mediaListEntry,const DeepCollectionEquality().hash(recommendedAnimes),const DeepCollectionEquality().hash(characters));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ShikimoriAnimeDetailsModel(mediaListEntry: $mediaListEntry, recommendedAnimes: $recommendedAnimes, characters: $characters)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ShikimoriAnimeDetailsModelCopyWith<$Res> {
|
||||
factory $ShikimoriAnimeDetailsModelCopyWith(ShikimoriAnimeDetailsModel value, $Res Function(ShikimoriAnimeDetailsModel) _then) = _$ShikimoriAnimeDetailsModelCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
@MediaListEntryConverter() MediaListEntry mediaListEntry,@AnimeConverter() List<Anime> recommendedAnimes,@MediaCharacterConverter() List<MediaCharacter> characters
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ShikimoriAnimeDetailsModelCopyWithImpl<$Res>
|
||||
implements $ShikimoriAnimeDetailsModelCopyWith<$Res> {
|
||||
_$ShikimoriAnimeDetailsModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ShikimoriAnimeDetailsModel _self;
|
||||
final $Res Function(ShikimoriAnimeDetailsModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriAnimeDetailsModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? mediaListEntry = null,Object? recommendedAnimes = null,Object? characters = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
mediaListEntry: null == mediaListEntry ? _self.mediaListEntry : mediaListEntry // ignore: cast_nullable_to_non_nullable
|
||||
as MediaListEntry,recommendedAnimes: null == recommendedAnimes ? _self.recommendedAnimes : recommendedAnimes // ignore: cast_nullable_to_non_nullable
|
||||
as List<Anime>,characters: null == characters ? _self.characters : characters // ignore: cast_nullable_to_non_nullable
|
||||
as List<MediaCharacter>,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ShikimoriAnimeDetailsModel].
|
||||
extension ShikimoriAnimeDetailsModelPatterns on ShikimoriAnimeDetailsModel {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ShikimoriAnimeDetailsModel value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeDetailsModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ShikimoriAnimeDetailsModel value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeDetailsModel():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ShikimoriAnimeDetailsModel value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeDetailsModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@MediaListEntryConverter() MediaListEntry mediaListEntry, @AnimeConverter() List<Anime> recommendedAnimes, @MediaCharacterConverter() List<MediaCharacter> characters)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeDetailsModel() when $default != null:
|
||||
return $default(_that.mediaListEntry,_that.recommendedAnimes,_that.characters);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@MediaListEntryConverter() MediaListEntry mediaListEntry, @AnimeConverter() List<Anime> recommendedAnimes, @MediaCharacterConverter() List<MediaCharacter> characters) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeDetailsModel():
|
||||
return $default(_that.mediaListEntry,_that.recommendedAnimes,_that.characters);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@MediaListEntryConverter() MediaListEntry mediaListEntry, @AnimeConverter() List<Anime> recommendedAnimes, @MediaCharacterConverter() List<MediaCharacter> characters)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeDetailsModel() when $default != null:
|
||||
return $default(_that.mediaListEntry,_that.recommendedAnimes,_that.characters);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _ShikimoriAnimeDetailsModel implements ShikimoriAnimeDetailsModel {
|
||||
const _ShikimoriAnimeDetailsModel({@MediaListEntryConverter() required this.mediaListEntry, @AnimeConverter() required final List<Anime> recommendedAnimes, @MediaCharacterConverter() required final List<MediaCharacter> characters}): _recommendedAnimes = recommendedAnimes,_characters = characters;
|
||||
factory _ShikimoriAnimeDetailsModel.fromJson(Map<String, dynamic> json) => _$ShikimoriAnimeDetailsModelFromJson(json);
|
||||
|
||||
@override@MediaListEntryConverter() final MediaListEntry mediaListEntry;
|
||||
final List<Anime> _recommendedAnimes;
|
||||
@override@AnimeConverter() List<Anime> get recommendedAnimes {
|
||||
if (_recommendedAnimes is EqualUnmodifiableListView) return _recommendedAnimes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_recommendedAnimes);
|
||||
}
|
||||
|
||||
final List<MediaCharacter> _characters;
|
||||
@override@MediaCharacterConverter() List<MediaCharacter> get characters {
|
||||
if (_characters is EqualUnmodifiableListView) return _characters;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_characters);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of ShikimoriAnimeDetailsModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ShikimoriAnimeDetailsModelCopyWith<_ShikimoriAnimeDetailsModel> get copyWith => __$ShikimoriAnimeDetailsModelCopyWithImpl<_ShikimoriAnimeDetailsModel>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$ShikimoriAnimeDetailsModelToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ShikimoriAnimeDetailsModel&&(identical(other.mediaListEntry, mediaListEntry) || other.mediaListEntry == mediaListEntry)&&const DeepCollectionEquality().equals(other._recommendedAnimes, _recommendedAnimes)&&const DeepCollectionEquality().equals(other._characters, _characters));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,mediaListEntry,const DeepCollectionEquality().hash(_recommendedAnimes),const DeepCollectionEquality().hash(_characters));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ShikimoriAnimeDetailsModel(mediaListEntry: $mediaListEntry, recommendedAnimes: $recommendedAnimes, characters: $characters)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ShikimoriAnimeDetailsModelCopyWith<$Res> implements $ShikimoriAnimeDetailsModelCopyWith<$Res> {
|
||||
factory _$ShikimoriAnimeDetailsModelCopyWith(_ShikimoriAnimeDetailsModel value, $Res Function(_ShikimoriAnimeDetailsModel) _then) = __$ShikimoriAnimeDetailsModelCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
@MediaListEntryConverter() MediaListEntry mediaListEntry,@AnimeConverter() List<Anime> recommendedAnimes,@MediaCharacterConverter() List<MediaCharacter> characters
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ShikimoriAnimeDetailsModelCopyWithImpl<$Res>
|
||||
implements _$ShikimoriAnimeDetailsModelCopyWith<$Res> {
|
||||
__$ShikimoriAnimeDetailsModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ShikimoriAnimeDetailsModel _self;
|
||||
final $Res Function(_ShikimoriAnimeDetailsModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriAnimeDetailsModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? mediaListEntry = null,Object? recommendedAnimes = null,Object? characters = null,}) {
|
||||
return _then(_ShikimoriAnimeDetailsModel(
|
||||
mediaListEntry: null == mediaListEntry ? _self.mediaListEntry : mediaListEntry // ignore: cast_nullable_to_non_nullable
|
||||
as MediaListEntry,recommendedAnimes: null == recommendedAnimes ? _self._recommendedAnimes : recommendedAnimes // ignore: cast_nullable_to_non_nullable
|
||||
as List<Anime>,characters: null == characters ? _self._characters : characters // ignore: cast_nullable_to_non_nullable
|
||||
as List<MediaCharacter>,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -0,0 +1,38 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'shikimori_anime_details.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_ShikimoriAnimeDetailsModel _$ShikimoriAnimeDetailsModelFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _ShikimoriAnimeDetailsModel(
|
||||
mediaListEntry: const MediaListEntryConverter().fromJson(
|
||||
json['mediaListEntry'] as Map<String, dynamic>,
|
||||
),
|
||||
recommendedAnimes: (json['recommendedAnimes'] as List<dynamic>)
|
||||
.map((e) => const AnimeConverter().fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
characters: (json['characters'] as List<dynamic>)
|
||||
.map(
|
||||
(e) =>
|
||||
const MediaCharacterConverter().fromJson(e as Map<String, dynamic>),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ShikimoriAnimeDetailsModelToJson(
|
||||
_ShikimoriAnimeDetailsModel instance,
|
||||
) => <String, dynamic>{
|
||||
'mediaListEntry': const MediaListEntryConverter().toJson(
|
||||
instance.mediaListEntry,
|
||||
),
|
||||
'recommendedAnimes': instance.recommendedAnimes
|
||||
.map(const AnimeConverter().toJson)
|
||||
.toList(),
|
||||
'characters': instance.characters
|
||||
.map(const MediaCharacterConverter().toJson)
|
||||
.toList(),
|
||||
};
|
||||
195
lib/data/models/shikimori/media/shikimori_anime_model.dart
Normal file
195
lib/data/models/shikimori/media/shikimori_anime_model.dart
Normal file
@@ -0,0 +1,195 @@
|
||||
// External dependencies
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
// Internal dependencies
|
||||
import 'package:unyo/domain/entities/media/airing_episode.dart';
|
||||
import 'package:unyo/domain/entities/media/anime.dart';
|
||||
import 'package:unyo/domain/entities/media/title.dart';
|
||||
|
||||
part 'shikimori_anime_model.freezed.dart';
|
||||
part 'shikimori_anime_model.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ShikimoriAnimeModel with _$ShikimoriAnimeModel implements Anime {
|
||||
const ShikimoriAnimeModel._();
|
||||
|
||||
factory ShikimoriAnimeModel({
|
||||
required int id,
|
||||
required int idMal,
|
||||
@TitleConverter() required Title title,
|
||||
required int averageScore,
|
||||
required String bannerImage,
|
||||
required String countryOfOrigin,
|
||||
required String coverImage,
|
||||
required String description,
|
||||
required int duration,
|
||||
required String endDate,
|
||||
required String startDate,
|
||||
required int episodes,
|
||||
required List<String> genres,
|
||||
required String format,
|
||||
required bool isAdult,
|
||||
required int popularity,
|
||||
required int meanScore,
|
||||
required String season,
|
||||
required String status,
|
||||
required bool isFavourite,
|
||||
@AiringEpisodeConverter() required AiringEpisode nextAiringEpisode,
|
||||
}) = _ShikimoriAnimeModel;
|
||||
|
||||
factory ShikimoriAnimeModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$ShikimoriAnimeModelFromJson(json);
|
||||
|
||||
// factory ShikimoriAnimeModel.fromListEntry(
|
||||
// ShikimoriAnimeListGraphqlAnimes entry,) {
|
||||
// return ShikimoriAnimeModel(
|
||||
// id: int.parse(entry.id),
|
||||
// idMal: int.tryParse(entry.malId) ?? -1,
|
||||
// title: TitleModel(
|
||||
// romaji: entry.name,
|
||||
// english: entry.english,
|
||||
// userPreferred: entry.name,
|
||||
// nativeTitle: entry.japanese,
|
||||
// ),
|
||||
// averageScore: (entry.score * 10).round(),
|
||||
// bannerImage: entry.poster.originalUrl,
|
||||
// countryOfOrigin: 'JP',
|
||||
// coverImage: entry.poster.mainUrl,
|
||||
// description: '',
|
||||
// duration: entry.duration,
|
||||
// endDate: _formatIncompleteDate(entry.releasedOn),
|
||||
// startDate: _formatIncompleteDate(entry.airedOn),
|
||||
// episodes: entry.episodes,
|
||||
// genres: entry.genres.map((g) => g.name).toList(),
|
||||
// format: _mapKindToFormat(entry.kind),
|
||||
// isAdult: entry.rating == 'rx' || !entry.isCensored,
|
||||
// popularity: 0,
|
||||
// meanScore: (entry.score * 10).round(),
|
||||
// season: entry.season,
|
||||
// status: _mapStatusToAnilist(entry.status),
|
||||
// isFavourite: false,
|
||||
// nextAiringEpisode: AiringEpisodeModel(
|
||||
// episode: entry.episodesAired,
|
||||
// airingAt: entry.nextEpisodeAt is String ? entry.nextEpisodeAt as String : '',
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
// factory ShikimoriAnimeModel.fromDetailsEntry(
|
||||
// ShikimoriAnimeDetailsGraphqlAnime entry,) {
|
||||
// return ShikimoriAnimeModel(
|
||||
// id: int.parse(entry.id),
|
||||
// idMal: int.tryParse(entry.malId) ?? -1,
|
||||
// title: TitleModel(
|
||||
// romaji: entry.name,
|
||||
// english: entry.english,
|
||||
// userPreferred: entry.name,
|
||||
// nativeTitle: entry.japanese,
|
||||
// ),
|
||||
// averageScore: (entry.score * 10).round(),
|
||||
// bannerImage: entry.poster.originalUrl,
|
||||
// countryOfOrigin: 'JP',
|
||||
// coverImage: entry.poster.mainUrl,
|
||||
// description: entry.description,
|
||||
// duration: entry.duration,
|
||||
// endDate: _formatIncompleteDate(entry.releasedOn),
|
||||
// startDate: _formatIncompleteDate(entry.airedOn),
|
||||
// episodes: entry.episodes,
|
||||
// genres: entry.genres.map((g) => g.name).toList(),
|
||||
// format: _mapKindToFormat(entry.kind),
|
||||
// isAdult: entry.rating == 'rx' || !entry.isCensored,
|
||||
// popularity: entry.scoresStats.fold(0, (sum, s) => sum + s.count),
|
||||
// meanScore: (entry.score * 10).round(),
|
||||
// season: entry.season,
|
||||
// status: _mapStatusToAnilist(entry.status),
|
||||
// isFavourite: false,
|
||||
// nextAiringEpisode: AiringEpisodeModel(
|
||||
// episode: entry.episodesAired,
|
||||
// airingAt: entry.nextEpisodeAt is String ? entry.nextEpisodeAt as String : '',
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
// factory ShikimoriAnimeModel.fromRelatedEntry(
|
||||
// ShikimoriAnimeDetailsGraphqlAnimeRelatedAnime entry,) {
|
||||
// return ShikimoriAnimeModel(
|
||||
// id: int.parse(entry.id),
|
||||
// idMal: -1,
|
||||
// title: TitleModel(
|
||||
// romaji: entry.name,
|
||||
// english: '',
|
||||
// userPreferred: entry.name,
|
||||
// nativeTitle: '',
|
||||
// ),
|
||||
// averageScore: 0,
|
||||
// bannerImage: entry.poster.mainUrl,
|
||||
// countryOfOrigin: 'JP',
|
||||
// coverImage: entry.poster.mainUrl,
|
||||
// description: '',
|
||||
// duration: 0,
|
||||
// endDate: '',
|
||||
// startDate: '',
|
||||
// episodes: entry.episodes,
|
||||
// genres: [],
|
||||
// format: _mapKindToFormat(entry.kind),
|
||||
// isAdult: false,
|
||||
// popularity: 0,
|
||||
// meanScore: 0,
|
||||
// season: '',
|
||||
// status: 'FINISHED',
|
||||
// isFavourite: false,
|
||||
// nextAiringEpisode: AiringEpisodeModel.empty(),
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
String _formatIncompleteDate(dynamic dateObj) {
|
||||
if (dateObj == null) return '';
|
||||
final year = dateObj.year;
|
||||
final month = dateObj.month;
|
||||
final day = dateObj.day;
|
||||
if (year == 0 && month == 0 && day == 0) return '';
|
||||
final parts = <String>[];
|
||||
if (day > 0) parts.add(day.toString().padLeft(2, '0'));
|
||||
if (month > 0) parts.add(month.toString().padLeft(2, '0'));
|
||||
if (year > 0) parts.add(year.toString());
|
||||
return parts.join('/');
|
||||
}
|
||||
|
||||
String _mapKindToFormat(String kind) {
|
||||
switch (kind) {
|
||||
case 'tv':
|
||||
return 'TV';
|
||||
case 'movie':
|
||||
return 'MOVIE';
|
||||
case 'ova':
|
||||
return 'OVA';
|
||||
case 'ona':
|
||||
return 'ONA';
|
||||
case 'special':
|
||||
return 'SPECIAL';
|
||||
case 'tv_special':
|
||||
return 'TV_SHORT';
|
||||
case 'music':
|
||||
return 'MUSIC';
|
||||
case 'pv':
|
||||
return 'MUSIC';
|
||||
case 'cm':
|
||||
return 'SPECIAL';
|
||||
default:
|
||||
return kind.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
String _mapStatusToAnilist(String status) {
|
||||
switch (status) {
|
||||
case 'anons':
|
||||
return 'NOT_YET_RELEASED';
|
||||
case 'ongoing':
|
||||
return 'RELEASING';
|
||||
case 'released':
|
||||
return 'FINISHED';
|
||||
default:
|
||||
return status.toUpperCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'shikimori_anime_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ShikimoriAnimeModel {
|
||||
|
||||
int get id; int get idMal;@TitleConverter() Title get title; int get averageScore; String get bannerImage; String get countryOfOrigin; String get coverImage; String get description; int get duration; String get endDate; String get startDate; int get episodes; List<String> get genres; String get format; bool get isAdult; int get popularity; int get meanScore; String get season; String get status; bool get isFavourite;@AiringEpisodeConverter() AiringEpisode get nextAiringEpisode;
|
||||
/// Create a copy of ShikimoriAnimeModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ShikimoriAnimeModelCopyWith<ShikimoriAnimeModel> get copyWith => _$ShikimoriAnimeModelCopyWithImpl<ShikimoriAnimeModel>(this as ShikimoriAnimeModel, _$identity);
|
||||
|
||||
/// Serializes this ShikimoriAnimeModel to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ShikimoriAnimeModel&&(identical(other.id, id) || other.id == id)&&(identical(other.idMal, idMal) || other.idMal == idMal)&&(identical(other.title, title) || other.title == title)&&(identical(other.averageScore, averageScore) || other.averageScore == averageScore)&&(identical(other.bannerImage, bannerImage) || other.bannerImage == bannerImage)&&(identical(other.countryOfOrigin, countryOfOrigin) || other.countryOfOrigin == countryOfOrigin)&&(identical(other.coverImage, coverImage) || other.coverImage == coverImage)&&(identical(other.description, description) || other.description == description)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.endDate, endDate) || other.endDate == endDate)&&(identical(other.startDate, startDate) || other.startDate == startDate)&&(identical(other.episodes, episodes) || other.episodes == episodes)&&const DeepCollectionEquality().equals(other.genres, genres)&&(identical(other.format, format) || other.format == format)&&(identical(other.isAdult, isAdult) || other.isAdult == isAdult)&&(identical(other.popularity, popularity) || other.popularity == popularity)&&(identical(other.meanScore, meanScore) || other.meanScore == meanScore)&&(identical(other.season, season) || other.season == season)&&(identical(other.status, status) || other.status == status)&&(identical(other.isFavourite, isFavourite) || other.isFavourite == isFavourite)&&(identical(other.nextAiringEpisode, nextAiringEpisode) || other.nextAiringEpisode == nextAiringEpisode));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,id,idMal,title,averageScore,bannerImage,countryOfOrigin,coverImage,description,duration,endDate,startDate,episodes,const DeepCollectionEquality().hash(genres),format,isAdult,popularity,meanScore,season,status,isFavourite,nextAiringEpisode]);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ShikimoriAnimeModelCopyWith<$Res> {
|
||||
factory $ShikimoriAnimeModelCopyWith(ShikimoriAnimeModel value, $Res Function(ShikimoriAnimeModel) _then) = _$ShikimoriAnimeModelCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
int id, int idMal,@TitleConverter() Title title, int averageScore, String bannerImage, String countryOfOrigin, String coverImage, String description, int duration, String endDate, String startDate, int episodes, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String season, String status, bool isFavourite,@AiringEpisodeConverter() AiringEpisode nextAiringEpisode
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ShikimoriAnimeModelCopyWithImpl<$Res>
|
||||
implements $ShikimoriAnimeModelCopyWith<$Res> {
|
||||
_$ShikimoriAnimeModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ShikimoriAnimeModel _self;
|
||||
final $Res Function(ShikimoriAnimeModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriAnimeModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? idMal = null,Object? title = null,Object? averageScore = null,Object? bannerImage = null,Object? countryOfOrigin = null,Object? coverImage = null,Object? description = null,Object? duration = null,Object? endDate = null,Object? startDate = null,Object? episodes = null,Object? genres = null,Object? format = null,Object? isAdult = null,Object? popularity = null,Object? meanScore = null,Object? season = null,Object? status = null,Object? isFavourite = null,Object? nextAiringEpisode = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as int,idMal: null == idMal ? _self.idMal : idMal // ignore: cast_nullable_to_non_nullable
|
||||
as int,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||
as Title,averageScore: null == averageScore ? _self.averageScore : averageScore // ignore: cast_nullable_to_non_nullable
|
||||
as int,bannerImage: null == bannerImage ? _self.bannerImage : bannerImage // ignore: cast_nullable_to_non_nullable
|
||||
as String,countryOfOrigin: null == countryOfOrigin ? _self.countryOfOrigin : countryOfOrigin // ignore: cast_nullable_to_non_nullable
|
||||
as String,coverImage: null == coverImage ? _self.coverImage : coverImage // ignore: cast_nullable_to_non_nullable
|
||||
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||
as String,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
||||
as int,endDate: null == endDate ? _self.endDate : endDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,startDate: null == startDate ? _self.startDate : startDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,episodes: null == episodes ? _self.episodes : episodes // ignore: cast_nullable_to_non_nullable
|
||||
as int,genres: null == genres ? _self.genres : genres // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,format: null == format ? _self.format : format // ignore: cast_nullable_to_non_nullable
|
||||
as String,isAdult: null == isAdult ? _self.isAdult : isAdult // ignore: cast_nullable_to_non_nullable
|
||||
as bool,popularity: null == popularity ? _self.popularity : popularity // ignore: cast_nullable_to_non_nullable
|
||||
as int,meanScore: null == meanScore ? _self.meanScore : meanScore // ignore: cast_nullable_to_non_nullable
|
||||
as int,season: null == season ? _self.season : season // ignore: cast_nullable_to_non_nullable
|
||||
as String,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||
as String,isFavourite: null == isFavourite ? _self.isFavourite : isFavourite // ignore: cast_nullable_to_non_nullable
|
||||
as bool,nextAiringEpisode: null == nextAiringEpisode ? _self.nextAiringEpisode : nextAiringEpisode // ignore: cast_nullable_to_non_nullable
|
||||
as AiringEpisode,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ShikimoriAnimeModel].
|
||||
extension ShikimoriAnimeModelPatterns on ShikimoriAnimeModel {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ShikimoriAnimeModel value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ShikimoriAnimeModel value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeModel():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ShikimoriAnimeModel value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int id, int idMal, @TitleConverter() Title title, int averageScore, String bannerImage, String countryOfOrigin, String coverImage, String description, int duration, String endDate, String startDate, int episodes, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String season, String status, bool isFavourite, @AiringEpisodeConverter() AiringEpisode nextAiringEpisode)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeModel() when $default != null:
|
||||
return $default(_that.id,_that.idMal,_that.title,_that.averageScore,_that.bannerImage,_that.countryOfOrigin,_that.coverImage,_that.description,_that.duration,_that.endDate,_that.startDate,_that.episodes,_that.genres,_that.format,_that.isAdult,_that.popularity,_that.meanScore,_that.season,_that.status,_that.isFavourite,_that.nextAiringEpisode);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int id, int idMal, @TitleConverter() Title title, int averageScore, String bannerImage, String countryOfOrigin, String coverImage, String description, int duration, String endDate, String startDate, int episodes, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String season, String status, bool isFavourite, @AiringEpisodeConverter() AiringEpisode nextAiringEpisode) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeModel():
|
||||
return $default(_that.id,_that.idMal,_that.title,_that.averageScore,_that.bannerImage,_that.countryOfOrigin,_that.coverImage,_that.description,_that.duration,_that.endDate,_that.startDate,_that.episodes,_that.genres,_that.format,_that.isAdult,_that.popularity,_that.meanScore,_that.season,_that.status,_that.isFavourite,_that.nextAiringEpisode);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int id, int idMal, @TitleConverter() Title title, int averageScore, String bannerImage, String countryOfOrigin, String coverImage, String description, int duration, String endDate, String startDate, int episodes, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String season, String status, bool isFavourite, @AiringEpisodeConverter() AiringEpisode nextAiringEpisode)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriAnimeModel() when $default != null:
|
||||
return $default(_that.id,_that.idMal,_that.title,_that.averageScore,_that.bannerImage,_that.countryOfOrigin,_that.coverImage,_that.description,_that.duration,_that.endDate,_that.startDate,_that.episodes,_that.genres,_that.format,_that.isAdult,_that.popularity,_that.meanScore,_that.season,_that.status,_that.isFavourite,_that.nextAiringEpisode);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _ShikimoriAnimeModel extends ShikimoriAnimeModel {
|
||||
_ShikimoriAnimeModel({required this.id, required this.idMal, @TitleConverter() required this.title, required this.averageScore, required this.bannerImage, required this.countryOfOrigin, required this.coverImage, required this.description, required this.duration, required this.endDate, required this.startDate, required this.episodes, required final List<String> genres, required this.format, required this.isAdult, required this.popularity, required this.meanScore, required this.season, required this.status, required this.isFavourite, @AiringEpisodeConverter() required this.nextAiringEpisode}): _genres = genres,super._();
|
||||
factory _ShikimoriAnimeModel.fromJson(Map<String, dynamic> json) => _$ShikimoriAnimeModelFromJson(json);
|
||||
|
||||
@override final int id;
|
||||
@override final int idMal;
|
||||
@override@TitleConverter() final Title title;
|
||||
@override final int averageScore;
|
||||
@override final String bannerImage;
|
||||
@override final String countryOfOrigin;
|
||||
@override final String coverImage;
|
||||
@override final String description;
|
||||
@override final int duration;
|
||||
@override final String endDate;
|
||||
@override final String startDate;
|
||||
@override final int episodes;
|
||||
final List<String> _genres;
|
||||
@override List<String> get genres {
|
||||
if (_genres is EqualUnmodifiableListView) return _genres;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_genres);
|
||||
}
|
||||
|
||||
@override final String format;
|
||||
@override final bool isAdult;
|
||||
@override final int popularity;
|
||||
@override final int meanScore;
|
||||
@override final String season;
|
||||
@override final String status;
|
||||
@override final bool isFavourite;
|
||||
@override@AiringEpisodeConverter() final AiringEpisode nextAiringEpisode;
|
||||
|
||||
/// Create a copy of ShikimoriAnimeModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ShikimoriAnimeModelCopyWith<_ShikimoriAnimeModel> get copyWith => __$ShikimoriAnimeModelCopyWithImpl<_ShikimoriAnimeModel>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$ShikimoriAnimeModelToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ShikimoriAnimeModel&&(identical(other.id, id) || other.id == id)&&(identical(other.idMal, idMal) || other.idMal == idMal)&&(identical(other.title, title) || other.title == title)&&(identical(other.averageScore, averageScore) || other.averageScore == averageScore)&&(identical(other.bannerImage, bannerImage) || other.bannerImage == bannerImage)&&(identical(other.countryOfOrigin, countryOfOrigin) || other.countryOfOrigin == countryOfOrigin)&&(identical(other.coverImage, coverImage) || other.coverImage == coverImage)&&(identical(other.description, description) || other.description == description)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.endDate, endDate) || other.endDate == endDate)&&(identical(other.startDate, startDate) || other.startDate == startDate)&&(identical(other.episodes, episodes) || other.episodes == episodes)&&const DeepCollectionEquality().equals(other._genres, _genres)&&(identical(other.format, format) || other.format == format)&&(identical(other.isAdult, isAdult) || other.isAdult == isAdult)&&(identical(other.popularity, popularity) || other.popularity == popularity)&&(identical(other.meanScore, meanScore) || other.meanScore == meanScore)&&(identical(other.season, season) || other.season == season)&&(identical(other.status, status) || other.status == status)&&(identical(other.isFavourite, isFavourite) || other.isFavourite == isFavourite)&&(identical(other.nextAiringEpisode, nextAiringEpisode) || other.nextAiringEpisode == nextAiringEpisode));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,id,idMal,title,averageScore,bannerImage,countryOfOrigin,coverImage,description,duration,endDate,startDate,episodes,const DeepCollectionEquality().hash(_genres),format,isAdult,popularity,meanScore,season,status,isFavourite,nextAiringEpisode]);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ShikimoriAnimeModelCopyWith<$Res> implements $ShikimoriAnimeModelCopyWith<$Res> {
|
||||
factory _$ShikimoriAnimeModelCopyWith(_ShikimoriAnimeModel value, $Res Function(_ShikimoriAnimeModel) _then) = __$ShikimoriAnimeModelCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
int id, int idMal,@TitleConverter() Title title, int averageScore, String bannerImage, String countryOfOrigin, String coverImage, String description, int duration, String endDate, String startDate, int episodes, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String season, String status, bool isFavourite,@AiringEpisodeConverter() AiringEpisode nextAiringEpisode
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ShikimoriAnimeModelCopyWithImpl<$Res>
|
||||
implements _$ShikimoriAnimeModelCopyWith<$Res> {
|
||||
__$ShikimoriAnimeModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ShikimoriAnimeModel _self;
|
||||
final $Res Function(_ShikimoriAnimeModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriAnimeModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? idMal = null,Object? title = null,Object? averageScore = null,Object? bannerImage = null,Object? countryOfOrigin = null,Object? coverImage = null,Object? description = null,Object? duration = null,Object? endDate = null,Object? startDate = null,Object? episodes = null,Object? genres = null,Object? format = null,Object? isAdult = null,Object? popularity = null,Object? meanScore = null,Object? season = null,Object? status = null,Object? isFavourite = null,Object? nextAiringEpisode = null,}) {
|
||||
return _then(_ShikimoriAnimeModel(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as int,idMal: null == idMal ? _self.idMal : idMal // ignore: cast_nullable_to_non_nullable
|
||||
as int,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||
as Title,averageScore: null == averageScore ? _self.averageScore : averageScore // ignore: cast_nullable_to_non_nullable
|
||||
as int,bannerImage: null == bannerImage ? _self.bannerImage : bannerImage // ignore: cast_nullable_to_non_nullable
|
||||
as String,countryOfOrigin: null == countryOfOrigin ? _self.countryOfOrigin : countryOfOrigin // ignore: cast_nullable_to_non_nullable
|
||||
as String,coverImage: null == coverImage ? _self.coverImage : coverImage // ignore: cast_nullable_to_non_nullable
|
||||
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||
as String,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
||||
as int,endDate: null == endDate ? _self.endDate : endDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,startDate: null == startDate ? _self.startDate : startDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,episodes: null == episodes ? _self.episodes : episodes // ignore: cast_nullable_to_non_nullable
|
||||
as int,genres: null == genres ? _self._genres : genres // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,format: null == format ? _self.format : format // ignore: cast_nullable_to_non_nullable
|
||||
as String,isAdult: null == isAdult ? _self.isAdult : isAdult // ignore: cast_nullable_to_non_nullable
|
||||
as bool,popularity: null == popularity ? _self.popularity : popularity // ignore: cast_nullable_to_non_nullable
|
||||
as int,meanScore: null == meanScore ? _self.meanScore : meanScore // ignore: cast_nullable_to_non_nullable
|
||||
as int,season: null == season ? _self.season : season // ignore: cast_nullable_to_non_nullable
|
||||
as String,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||
as String,isFavourite: null == isFavourite ? _self.isFavourite : isFavourite // ignore: cast_nullable_to_non_nullable
|
||||
as bool,nextAiringEpisode: null == nextAiringEpisode ? _self.nextAiringEpisode : nextAiringEpisode // ignore: cast_nullable_to_non_nullable
|
||||
as AiringEpisode,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
63
lib/data/models/shikimori/media/shikimori_anime_model.g.dart
Normal file
63
lib/data/models/shikimori/media/shikimori_anime_model.g.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'shikimori_anime_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_ShikimoriAnimeModel _$ShikimoriAnimeModelFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _ShikimoriAnimeModel(
|
||||
id: (json['id'] as num).toInt(),
|
||||
idMal: (json['idMal'] as num).toInt(),
|
||||
title: const TitleConverter().fromJson(json['title'] as Map<String, dynamic>),
|
||||
averageScore: (json['averageScore'] as num).toInt(),
|
||||
bannerImage: json['bannerImage'] as String,
|
||||
countryOfOrigin: json['countryOfOrigin'] as String,
|
||||
coverImage: json['coverImage'] as String,
|
||||
description: json['description'] as String,
|
||||
duration: (json['duration'] as num).toInt(),
|
||||
endDate: json['endDate'] as String,
|
||||
startDate: json['startDate'] as String,
|
||||
episodes: (json['episodes'] as num).toInt(),
|
||||
genres: (json['genres'] as List<dynamic>).map((e) => e as String).toList(),
|
||||
format: json['format'] as String,
|
||||
isAdult: json['isAdult'] as bool,
|
||||
popularity: (json['popularity'] as num).toInt(),
|
||||
meanScore: (json['meanScore'] as num).toInt(),
|
||||
season: json['season'] as String,
|
||||
status: json['status'] as String,
|
||||
isFavourite: json['isFavourite'] as bool,
|
||||
nextAiringEpisode: const AiringEpisodeConverter().fromJson(
|
||||
json['nextAiringEpisode'] as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ShikimoriAnimeModelToJson(
|
||||
_ShikimoriAnimeModel instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'idMal': instance.idMal,
|
||||
'title': const TitleConverter().toJson(instance.title),
|
||||
'averageScore': instance.averageScore,
|
||||
'bannerImage': instance.bannerImage,
|
||||
'countryOfOrigin': instance.countryOfOrigin,
|
||||
'coverImage': instance.coverImage,
|
||||
'description': instance.description,
|
||||
'duration': instance.duration,
|
||||
'endDate': instance.endDate,
|
||||
'startDate': instance.startDate,
|
||||
'episodes': instance.episodes,
|
||||
'genres': instance.genres,
|
||||
'format': instance.format,
|
||||
'isAdult': instance.isAdult,
|
||||
'popularity': instance.popularity,
|
||||
'meanScore': instance.meanScore,
|
||||
'season': instance.season,
|
||||
'status': instance.status,
|
||||
'isFavourite': instance.isFavourite,
|
||||
'nextAiringEpisode': const AiringEpisodeConverter().toJson(
|
||||
instance.nextAiringEpisode,
|
||||
),
|
||||
};
|
||||
55
lib/data/models/shikimori/media/shikimori_manga_details.dart
Normal file
55
lib/data/models/shikimori/media/shikimori_manga_details.dart
Normal file
@@ -0,0 +1,55 @@
|
||||
// External dependencies
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
// Internal dependencies
|
||||
import 'package:unyo/domain/entities/list/media_list_entry.dart';
|
||||
import 'package:unyo/domain/entities/media/manga.dart';
|
||||
import 'package:unyo/domain/entities/media/manga_details.dart';
|
||||
import 'package:unyo/domain/entities/media/media_character.dart';
|
||||
|
||||
part 'shikimori_manga_details.freezed.dart';
|
||||
part 'shikimori_manga_details.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ShikimoriMangaDetailsModel
|
||||
with _$ShikimoriMangaDetailsModel
|
||||
implements MangaDetails {
|
||||
const factory ShikimoriMangaDetailsModel({
|
||||
@MediaListEntryConverter() required MediaListEntry mediaListEntry,
|
||||
@MangaConverter() required List<Manga> recommendedMangas,
|
||||
@MediaCharacterConverter() required List<MediaCharacter> characters,
|
||||
}) = _ShikimoriMangaDetailsModel;
|
||||
|
||||
factory ShikimoriMangaDetailsModel.empty() => ShikimoriMangaDetailsModel(
|
||||
mediaListEntry: MediaListEntryModel.empty(),
|
||||
recommendedMangas: [],
|
||||
characters: [],
|
||||
);
|
||||
|
||||
factory ShikimoriMangaDetailsModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$ShikimoriMangaDetailsModelFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$ShikimoriMangaDetailsModelToJson(this as _ShikimoriMangaDetailsModel);
|
||||
|
||||
// factory ShikimoriMangaDetailsModel.fromDetailsEntry(
|
||||
// ShikimoriMangaDetailsGraphqlManga entry,) {
|
||||
// final recommendedMangas = <Manga>[];
|
||||
// for (final related in entry.related) {
|
||||
// recommendedMangas.add(
|
||||
// ShikimoriMangaModel.fromRelatedEntry(related.anime),
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// final characters = entry.characterRoles
|
||||
// .map((role) => ShikimoriMediaCharacterModel.fromMangaCharacterRole(role))
|
||||
// .toList();
|
||||
//
|
||||
// return ShikimoriMangaDetailsModel(
|
||||
// mediaListEntry: MediaListEntryModel.empty(),
|
||||
// recommendedMangas: recommendedMangas,
|
||||
// characters: characters,
|
||||
// );
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'shikimori_manga_details.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ShikimoriMangaDetailsModel {
|
||||
|
||||
@MediaListEntryConverter() MediaListEntry get mediaListEntry;@MangaConverter() List<Manga> get recommendedMangas;@MediaCharacterConverter() List<MediaCharacter> get characters;
|
||||
/// Create a copy of ShikimoriMangaDetailsModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ShikimoriMangaDetailsModelCopyWith<ShikimoriMangaDetailsModel> get copyWith => _$ShikimoriMangaDetailsModelCopyWithImpl<ShikimoriMangaDetailsModel>(this as ShikimoriMangaDetailsModel, _$identity);
|
||||
|
||||
/// Serializes this ShikimoriMangaDetailsModel to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ShikimoriMangaDetailsModel&&(identical(other.mediaListEntry, mediaListEntry) || other.mediaListEntry == mediaListEntry)&&const DeepCollectionEquality().equals(other.recommendedMangas, recommendedMangas)&&const DeepCollectionEquality().equals(other.characters, characters));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,mediaListEntry,const DeepCollectionEquality().hash(recommendedMangas),const DeepCollectionEquality().hash(characters));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ShikimoriMangaDetailsModel(mediaListEntry: $mediaListEntry, recommendedMangas: $recommendedMangas, characters: $characters)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ShikimoriMangaDetailsModelCopyWith<$Res> {
|
||||
factory $ShikimoriMangaDetailsModelCopyWith(ShikimoriMangaDetailsModel value, $Res Function(ShikimoriMangaDetailsModel) _then) = _$ShikimoriMangaDetailsModelCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
@MediaListEntryConverter() MediaListEntry mediaListEntry,@MangaConverter() List<Manga> recommendedMangas,@MediaCharacterConverter() List<MediaCharacter> characters
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ShikimoriMangaDetailsModelCopyWithImpl<$Res>
|
||||
implements $ShikimoriMangaDetailsModelCopyWith<$Res> {
|
||||
_$ShikimoriMangaDetailsModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ShikimoriMangaDetailsModel _self;
|
||||
final $Res Function(ShikimoriMangaDetailsModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriMangaDetailsModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? mediaListEntry = null,Object? recommendedMangas = null,Object? characters = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
mediaListEntry: null == mediaListEntry ? _self.mediaListEntry : mediaListEntry // ignore: cast_nullable_to_non_nullable
|
||||
as MediaListEntry,recommendedMangas: null == recommendedMangas ? _self.recommendedMangas : recommendedMangas // ignore: cast_nullable_to_non_nullable
|
||||
as List<Manga>,characters: null == characters ? _self.characters : characters // ignore: cast_nullable_to_non_nullable
|
||||
as List<MediaCharacter>,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ShikimoriMangaDetailsModel].
|
||||
extension ShikimoriMangaDetailsModelPatterns on ShikimoriMangaDetailsModel {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ShikimoriMangaDetailsModel value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaDetailsModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ShikimoriMangaDetailsModel value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaDetailsModel():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ShikimoriMangaDetailsModel value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaDetailsModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@MediaListEntryConverter() MediaListEntry mediaListEntry, @MangaConverter() List<Manga> recommendedMangas, @MediaCharacterConverter() List<MediaCharacter> characters)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaDetailsModel() when $default != null:
|
||||
return $default(_that.mediaListEntry,_that.recommendedMangas,_that.characters);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@MediaListEntryConverter() MediaListEntry mediaListEntry, @MangaConverter() List<Manga> recommendedMangas, @MediaCharacterConverter() List<MediaCharacter> characters) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaDetailsModel():
|
||||
return $default(_that.mediaListEntry,_that.recommendedMangas,_that.characters);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@MediaListEntryConverter() MediaListEntry mediaListEntry, @MangaConverter() List<Manga> recommendedMangas, @MediaCharacterConverter() List<MediaCharacter> characters)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaDetailsModel() when $default != null:
|
||||
return $default(_that.mediaListEntry,_that.recommendedMangas,_that.characters);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _ShikimoriMangaDetailsModel implements ShikimoriMangaDetailsModel {
|
||||
const _ShikimoriMangaDetailsModel({@MediaListEntryConverter() required this.mediaListEntry, @MangaConverter() required final List<Manga> recommendedMangas, @MediaCharacterConverter() required final List<MediaCharacter> characters}): _recommendedMangas = recommendedMangas,_characters = characters;
|
||||
factory _ShikimoriMangaDetailsModel.fromJson(Map<String, dynamic> json) => _$ShikimoriMangaDetailsModelFromJson(json);
|
||||
|
||||
@override@MediaListEntryConverter() final MediaListEntry mediaListEntry;
|
||||
final List<Manga> _recommendedMangas;
|
||||
@override@MangaConverter() List<Manga> get recommendedMangas {
|
||||
if (_recommendedMangas is EqualUnmodifiableListView) return _recommendedMangas;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_recommendedMangas);
|
||||
}
|
||||
|
||||
final List<MediaCharacter> _characters;
|
||||
@override@MediaCharacterConverter() List<MediaCharacter> get characters {
|
||||
if (_characters is EqualUnmodifiableListView) return _characters;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_characters);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of ShikimoriMangaDetailsModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ShikimoriMangaDetailsModelCopyWith<_ShikimoriMangaDetailsModel> get copyWith => __$ShikimoriMangaDetailsModelCopyWithImpl<_ShikimoriMangaDetailsModel>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$ShikimoriMangaDetailsModelToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ShikimoriMangaDetailsModel&&(identical(other.mediaListEntry, mediaListEntry) || other.mediaListEntry == mediaListEntry)&&const DeepCollectionEquality().equals(other._recommendedMangas, _recommendedMangas)&&const DeepCollectionEquality().equals(other._characters, _characters));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,mediaListEntry,const DeepCollectionEquality().hash(_recommendedMangas),const DeepCollectionEquality().hash(_characters));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ShikimoriMangaDetailsModel(mediaListEntry: $mediaListEntry, recommendedMangas: $recommendedMangas, characters: $characters)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ShikimoriMangaDetailsModelCopyWith<$Res> implements $ShikimoriMangaDetailsModelCopyWith<$Res> {
|
||||
factory _$ShikimoriMangaDetailsModelCopyWith(_ShikimoriMangaDetailsModel value, $Res Function(_ShikimoriMangaDetailsModel) _then) = __$ShikimoriMangaDetailsModelCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
@MediaListEntryConverter() MediaListEntry mediaListEntry,@MangaConverter() List<Manga> recommendedMangas,@MediaCharacterConverter() List<MediaCharacter> characters
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ShikimoriMangaDetailsModelCopyWithImpl<$Res>
|
||||
implements _$ShikimoriMangaDetailsModelCopyWith<$Res> {
|
||||
__$ShikimoriMangaDetailsModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ShikimoriMangaDetailsModel _self;
|
||||
final $Res Function(_ShikimoriMangaDetailsModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriMangaDetailsModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? mediaListEntry = null,Object? recommendedMangas = null,Object? characters = null,}) {
|
||||
return _then(_ShikimoriMangaDetailsModel(
|
||||
mediaListEntry: null == mediaListEntry ? _self.mediaListEntry : mediaListEntry // ignore: cast_nullable_to_non_nullable
|
||||
as MediaListEntry,recommendedMangas: null == recommendedMangas ? _self._recommendedMangas : recommendedMangas // ignore: cast_nullable_to_non_nullable
|
||||
as List<Manga>,characters: null == characters ? _self._characters : characters // ignore: cast_nullable_to_non_nullable
|
||||
as List<MediaCharacter>,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -0,0 +1,38 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'shikimori_manga_details.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_ShikimoriMangaDetailsModel _$ShikimoriMangaDetailsModelFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _ShikimoriMangaDetailsModel(
|
||||
mediaListEntry: const MediaListEntryConverter().fromJson(
|
||||
json['mediaListEntry'] as Map<String, dynamic>,
|
||||
),
|
||||
recommendedMangas: (json['recommendedMangas'] as List<dynamic>)
|
||||
.map((e) => const MangaConverter().fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
characters: (json['characters'] as List<dynamic>)
|
||||
.map(
|
||||
(e) =>
|
||||
const MediaCharacterConverter().fromJson(e as Map<String, dynamic>),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ShikimoriMangaDetailsModelToJson(
|
||||
_ShikimoriMangaDetailsModel instance,
|
||||
) => <String, dynamic>{
|
||||
'mediaListEntry': const MediaListEntryConverter().toJson(
|
||||
instance.mediaListEntry,
|
||||
),
|
||||
'recommendedMangas': instance.recommendedMangas
|
||||
.map(const MangaConverter().toJson)
|
||||
.toList(),
|
||||
'characters': instance.characters
|
||||
.map(const MediaCharacterConverter().toJson)
|
||||
.toList(),
|
||||
};
|
||||
177
lib/data/models/shikimori/media/shikimori_manga_model.dart
Normal file
177
lib/data/models/shikimori/media/shikimori_manga_model.dart
Normal file
@@ -0,0 +1,177 @@
|
||||
// External dependencies
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
// Internal dependencies
|
||||
import 'package:unyo/domain/entities/media/manga.dart';
|
||||
import 'package:unyo/domain/entities/media/title.dart';
|
||||
|
||||
part 'shikimori_manga_model.freezed.dart';
|
||||
part 'shikimori_manga_model.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ShikimoriMangaModel with _$ShikimoriMangaModel implements Manga {
|
||||
const ShikimoriMangaModel._();
|
||||
|
||||
factory ShikimoriMangaModel({
|
||||
required int id,
|
||||
required int idMal,
|
||||
@TitleConverter() required Title title,
|
||||
required int averageScore,
|
||||
required String bannerImage,
|
||||
required int chapters,
|
||||
required String countryOfOrigin,
|
||||
required String coverImage,
|
||||
required String description,
|
||||
required String endDate,
|
||||
required String startDate,
|
||||
required List<String> genres,
|
||||
required String format,
|
||||
required bool isAdult,
|
||||
required int popularity,
|
||||
required int meanScore,
|
||||
required String status,
|
||||
required bool isFavourite,
|
||||
}) = _ShikimoriMangaModel;
|
||||
|
||||
factory ShikimoriMangaModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$ShikimoriMangaModelFromJson(json);
|
||||
|
||||
// factory ShikimoriMangaModel.fromListEntry(
|
||||
// ShikimoriMangaListGraphqlMangas entry,) {
|
||||
// return ShikimoriMangaModel(
|
||||
// id: int.parse(entry.id),
|
||||
// idMal: int.tryParse(entry.malId) ?? -1,
|
||||
// title: TitleModel(
|
||||
// romaji: entry.name,
|
||||
// english: entry.english,
|
||||
// userPreferred: entry.name,
|
||||
// nativeTitle: entry.japanese,
|
||||
// ),
|
||||
// averageScore: (entry.score * 10).round(),
|
||||
// bannerImage: entry.poster.originalUrl,
|
||||
// chapters: entry.chapters,
|
||||
// countryOfOrigin: 'JP',
|
||||
// coverImage: entry.poster.mainUrl,
|
||||
// description: '',
|
||||
// endDate: _formatIncompleteDate(entry.releasedOn),
|
||||
// startDate: _formatIncompleteDate(entry.airedOn),
|
||||
// genres: entry.genres.map((g) => g.name).toList(),
|
||||
// format: _mapMangaKindToFormat(entry.kind),
|
||||
// isAdult: !entry.isCensored,
|
||||
// popularity: 0,
|
||||
// meanScore: (entry.score * 10).round(),
|
||||
// status: _mapMangaStatusToAnilist(entry.status),
|
||||
// isFavourite: false,
|
||||
// );
|
||||
// }
|
||||
|
||||
// factory ShikimoriMangaModel.fromDetailsEntry(
|
||||
// ShikimoriMangaDetailsGraphqlManga entry,) {
|
||||
// return ShikimoriMangaModel(
|
||||
// id: int.parse(entry.id),
|
||||
// idMal: int.tryParse(entry.malId) ?? -1,
|
||||
// title: TitleModel(
|
||||
// romaji: entry.name,
|
||||
// english: entry.english,
|
||||
// userPreferred: entry.name,
|
||||
// nativeTitle: entry.japanese,
|
||||
// ),
|
||||
// averageScore: (entry.score * 10).round(),
|
||||
// bannerImage: entry.poster.originalUrl,
|
||||
// chapters: entry.chapters,
|
||||
// countryOfOrigin: 'JP',
|
||||
// coverImage: entry.poster.mainUrl,
|
||||
// description: entry.description,
|
||||
// endDate: _formatIncompleteDate(entry.releasedOn),
|
||||
// startDate: _formatIncompleteDate(entry.airedOn),
|
||||
// genres: entry.genres.map((g) => g.name).toList(),
|
||||
// format: _mapMangaKindToFormat(entry.kind),
|
||||
// isAdult: !entry.isCensored,
|
||||
// popularity: 0,
|
||||
// meanScore: (entry.score * 10).round(),
|
||||
// status: _mapMangaStatusToAnilist(entry.status),
|
||||
// isFavourite: false,
|
||||
// );
|
||||
// }
|
||||
|
||||
// factory ShikimoriMangaModel.fromRelatedEntry(
|
||||
// ShikimoriMangaDetailsGraphqlMangaRelatedAnime entry,) {
|
||||
// return ShikimoriMangaModel(
|
||||
// id: int.parse(entry.id),
|
||||
// idMal: -1,
|
||||
// title: TitleModel(
|
||||
// romaji: entry.name,
|
||||
// english: '',
|
||||
// userPreferred: entry.name,
|
||||
// nativeTitle: '',
|
||||
// ),
|
||||
// averageScore: 0,
|
||||
// bannerImage: entry.poster.mainUrl,
|
||||
// chapters: entry.episodes,
|
||||
// countryOfOrigin: 'JP',
|
||||
// coverImage: entry.poster.mainUrl,
|
||||
// description: '',
|
||||
// endDate: '',
|
||||
// startDate: '',
|
||||
// genres: [],
|
||||
// format: _mapMangaKindToFormat(entry.kind),
|
||||
// isAdult: false,
|
||||
// popularity: 0,
|
||||
// meanScore: 0,
|
||||
// status: 'FINISHED',
|
||||
// isFavourite: false,
|
||||
// );
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
String _formatIncompleteDate(dynamic dateObj) {
|
||||
if (dateObj == null) return '';
|
||||
final year = dateObj.year;
|
||||
final month = dateObj.month;
|
||||
final day = dateObj.day;
|
||||
if (year == 0 && month == 0 && day == 0) return '';
|
||||
final parts = <String>[];
|
||||
if (day > 0) parts.add(day.toString().padLeft(2, '0'));
|
||||
if (month > 0) parts.add(month.toString().padLeft(2, '0'));
|
||||
if (year > 0) parts.add(year.toString());
|
||||
return parts.join('/');
|
||||
}
|
||||
|
||||
String _mapMangaKindToFormat(String kind) {
|
||||
switch (kind) {
|
||||
case 'manga':
|
||||
return 'MANGA';
|
||||
case 'manhwa':
|
||||
return 'MANHWA';
|
||||
case 'manhua':
|
||||
return 'MANHUA';
|
||||
case 'light_novel':
|
||||
return 'NOVEL';
|
||||
case 'novel':
|
||||
return 'NOVEL';
|
||||
case 'one_shot':
|
||||
return 'ONE_SHOT';
|
||||
case 'doujin':
|
||||
return 'DOUJINSHI';
|
||||
default:
|
||||
return kind.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
String _mapMangaStatusToAnilist(String status) {
|
||||
switch (status) {
|
||||
case 'anons':
|
||||
return 'NOT_YET_RELEASED';
|
||||
case 'ongoing':
|
||||
return 'RELEASING';
|
||||
case 'released':
|
||||
return 'FINISHED';
|
||||
case 'paused':
|
||||
return 'HIATUS';
|
||||
case 'discontinued':
|
||||
return 'CANCELLED';
|
||||
default:
|
||||
return status.toUpperCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'shikimori_manga_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ShikimoriMangaModel {
|
||||
|
||||
int get id; int get idMal;@TitleConverter() Title get title; int get averageScore; String get bannerImage; int get chapters; String get countryOfOrigin; String get coverImage; String get description; String get endDate; String get startDate; List<String> get genres; String get format; bool get isAdult; int get popularity; int get meanScore; String get status; bool get isFavourite;
|
||||
/// Create a copy of ShikimoriMangaModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ShikimoriMangaModelCopyWith<ShikimoriMangaModel> get copyWith => _$ShikimoriMangaModelCopyWithImpl<ShikimoriMangaModel>(this as ShikimoriMangaModel, _$identity);
|
||||
|
||||
/// Serializes this ShikimoriMangaModel to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ShikimoriMangaModel&&(identical(other.id, id) || other.id == id)&&(identical(other.idMal, idMal) || other.idMal == idMal)&&(identical(other.title, title) || other.title == title)&&(identical(other.averageScore, averageScore) || other.averageScore == averageScore)&&(identical(other.bannerImage, bannerImage) || other.bannerImage == bannerImage)&&(identical(other.chapters, chapters) || other.chapters == chapters)&&(identical(other.countryOfOrigin, countryOfOrigin) || other.countryOfOrigin == countryOfOrigin)&&(identical(other.coverImage, coverImage) || other.coverImage == coverImage)&&(identical(other.description, description) || other.description == description)&&(identical(other.endDate, endDate) || other.endDate == endDate)&&(identical(other.startDate, startDate) || other.startDate == startDate)&&const DeepCollectionEquality().equals(other.genres, genres)&&(identical(other.format, format) || other.format == format)&&(identical(other.isAdult, isAdult) || other.isAdult == isAdult)&&(identical(other.popularity, popularity) || other.popularity == popularity)&&(identical(other.meanScore, meanScore) || other.meanScore == meanScore)&&(identical(other.status, status) || other.status == status)&&(identical(other.isFavourite, isFavourite) || other.isFavourite == isFavourite));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,idMal,title,averageScore,bannerImage,chapters,countryOfOrigin,coverImage,description,endDate,startDate,const DeepCollectionEquality().hash(genres),format,isAdult,popularity,meanScore,status,isFavourite);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ShikimoriMangaModelCopyWith<$Res> {
|
||||
factory $ShikimoriMangaModelCopyWith(ShikimoriMangaModel value, $Res Function(ShikimoriMangaModel) _then) = _$ShikimoriMangaModelCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
int id, int idMal,@TitleConverter() Title title, int averageScore, String bannerImage, int chapters, String countryOfOrigin, String coverImage, String description, String endDate, String startDate, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String status, bool isFavourite
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ShikimoriMangaModelCopyWithImpl<$Res>
|
||||
implements $ShikimoriMangaModelCopyWith<$Res> {
|
||||
_$ShikimoriMangaModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ShikimoriMangaModel _self;
|
||||
final $Res Function(ShikimoriMangaModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriMangaModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? idMal = null,Object? title = null,Object? averageScore = null,Object? bannerImage = null,Object? chapters = null,Object? countryOfOrigin = null,Object? coverImage = null,Object? description = null,Object? endDate = null,Object? startDate = null,Object? genres = null,Object? format = null,Object? isAdult = null,Object? popularity = null,Object? meanScore = null,Object? status = null,Object? isFavourite = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as int,idMal: null == idMal ? _self.idMal : idMal // ignore: cast_nullable_to_non_nullable
|
||||
as int,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||
as Title,averageScore: null == averageScore ? _self.averageScore : averageScore // ignore: cast_nullable_to_non_nullable
|
||||
as int,bannerImage: null == bannerImage ? _self.bannerImage : bannerImage // ignore: cast_nullable_to_non_nullable
|
||||
as String,chapters: null == chapters ? _self.chapters : chapters // ignore: cast_nullable_to_non_nullable
|
||||
as int,countryOfOrigin: null == countryOfOrigin ? _self.countryOfOrigin : countryOfOrigin // ignore: cast_nullable_to_non_nullable
|
||||
as String,coverImage: null == coverImage ? _self.coverImage : coverImage // ignore: cast_nullable_to_non_nullable
|
||||
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||
as String,endDate: null == endDate ? _self.endDate : endDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,startDate: null == startDate ? _self.startDate : startDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,genres: null == genres ? _self.genres : genres // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,format: null == format ? _self.format : format // ignore: cast_nullable_to_non_nullable
|
||||
as String,isAdult: null == isAdult ? _self.isAdult : isAdult // ignore: cast_nullable_to_non_nullable
|
||||
as bool,popularity: null == popularity ? _self.popularity : popularity // ignore: cast_nullable_to_non_nullable
|
||||
as int,meanScore: null == meanScore ? _self.meanScore : meanScore // ignore: cast_nullable_to_non_nullable
|
||||
as int,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||
as String,isFavourite: null == isFavourite ? _self.isFavourite : isFavourite // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ShikimoriMangaModel].
|
||||
extension ShikimoriMangaModelPatterns on ShikimoriMangaModel {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ShikimoriMangaModel value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ShikimoriMangaModel value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaModel():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ShikimoriMangaModel value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int id, int idMal, @TitleConverter() Title title, int averageScore, String bannerImage, int chapters, String countryOfOrigin, String coverImage, String description, String endDate, String startDate, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String status, bool isFavourite)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaModel() when $default != null:
|
||||
return $default(_that.id,_that.idMal,_that.title,_that.averageScore,_that.bannerImage,_that.chapters,_that.countryOfOrigin,_that.coverImage,_that.description,_that.endDate,_that.startDate,_that.genres,_that.format,_that.isAdult,_that.popularity,_that.meanScore,_that.status,_that.isFavourite);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int id, int idMal, @TitleConverter() Title title, int averageScore, String bannerImage, int chapters, String countryOfOrigin, String coverImage, String description, String endDate, String startDate, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String status, bool isFavourite) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaModel():
|
||||
return $default(_that.id,_that.idMal,_that.title,_that.averageScore,_that.bannerImage,_that.chapters,_that.countryOfOrigin,_that.coverImage,_that.description,_that.endDate,_that.startDate,_that.genres,_that.format,_that.isAdult,_that.popularity,_that.meanScore,_that.status,_that.isFavourite);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int id, int idMal, @TitleConverter() Title title, int averageScore, String bannerImage, int chapters, String countryOfOrigin, String coverImage, String description, String endDate, String startDate, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String status, bool isFavourite)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMangaModel() when $default != null:
|
||||
return $default(_that.id,_that.idMal,_that.title,_that.averageScore,_that.bannerImage,_that.chapters,_that.countryOfOrigin,_that.coverImage,_that.description,_that.endDate,_that.startDate,_that.genres,_that.format,_that.isAdult,_that.popularity,_that.meanScore,_that.status,_that.isFavourite);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _ShikimoriMangaModel extends ShikimoriMangaModel {
|
||||
_ShikimoriMangaModel({required this.id, required this.idMal, @TitleConverter() required this.title, required this.averageScore, required this.bannerImage, required this.chapters, required this.countryOfOrigin, required this.coverImage, required this.description, required this.endDate, required this.startDate, required final List<String> genres, required this.format, required this.isAdult, required this.popularity, required this.meanScore, required this.status, required this.isFavourite}): _genres = genres,super._();
|
||||
factory _ShikimoriMangaModel.fromJson(Map<String, dynamic> json) => _$ShikimoriMangaModelFromJson(json);
|
||||
|
||||
@override final int id;
|
||||
@override final int idMal;
|
||||
@override@TitleConverter() final Title title;
|
||||
@override final int averageScore;
|
||||
@override final String bannerImage;
|
||||
@override final int chapters;
|
||||
@override final String countryOfOrigin;
|
||||
@override final String coverImage;
|
||||
@override final String description;
|
||||
@override final String endDate;
|
||||
@override final String startDate;
|
||||
final List<String> _genres;
|
||||
@override List<String> get genres {
|
||||
if (_genres is EqualUnmodifiableListView) return _genres;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_genres);
|
||||
}
|
||||
|
||||
@override final String format;
|
||||
@override final bool isAdult;
|
||||
@override final int popularity;
|
||||
@override final int meanScore;
|
||||
@override final String status;
|
||||
@override final bool isFavourite;
|
||||
|
||||
/// Create a copy of ShikimoriMangaModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ShikimoriMangaModelCopyWith<_ShikimoriMangaModel> get copyWith => __$ShikimoriMangaModelCopyWithImpl<_ShikimoriMangaModel>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$ShikimoriMangaModelToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ShikimoriMangaModel&&(identical(other.id, id) || other.id == id)&&(identical(other.idMal, idMal) || other.idMal == idMal)&&(identical(other.title, title) || other.title == title)&&(identical(other.averageScore, averageScore) || other.averageScore == averageScore)&&(identical(other.bannerImage, bannerImage) || other.bannerImage == bannerImage)&&(identical(other.chapters, chapters) || other.chapters == chapters)&&(identical(other.countryOfOrigin, countryOfOrigin) || other.countryOfOrigin == countryOfOrigin)&&(identical(other.coverImage, coverImage) || other.coverImage == coverImage)&&(identical(other.description, description) || other.description == description)&&(identical(other.endDate, endDate) || other.endDate == endDate)&&(identical(other.startDate, startDate) || other.startDate == startDate)&&const DeepCollectionEquality().equals(other._genres, _genres)&&(identical(other.format, format) || other.format == format)&&(identical(other.isAdult, isAdult) || other.isAdult == isAdult)&&(identical(other.popularity, popularity) || other.popularity == popularity)&&(identical(other.meanScore, meanScore) || other.meanScore == meanScore)&&(identical(other.status, status) || other.status == status)&&(identical(other.isFavourite, isFavourite) || other.isFavourite == isFavourite));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,idMal,title,averageScore,bannerImage,chapters,countryOfOrigin,coverImage,description,endDate,startDate,const DeepCollectionEquality().hash(_genres),format,isAdult,popularity,meanScore,status,isFavourite);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ShikimoriMangaModelCopyWith<$Res> implements $ShikimoriMangaModelCopyWith<$Res> {
|
||||
factory _$ShikimoriMangaModelCopyWith(_ShikimoriMangaModel value, $Res Function(_ShikimoriMangaModel) _then) = __$ShikimoriMangaModelCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
int id, int idMal,@TitleConverter() Title title, int averageScore, String bannerImage, int chapters, String countryOfOrigin, String coverImage, String description, String endDate, String startDate, List<String> genres, String format, bool isAdult, int popularity, int meanScore, String status, bool isFavourite
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ShikimoriMangaModelCopyWithImpl<$Res>
|
||||
implements _$ShikimoriMangaModelCopyWith<$Res> {
|
||||
__$ShikimoriMangaModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ShikimoriMangaModel _self;
|
||||
final $Res Function(_ShikimoriMangaModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriMangaModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? idMal = null,Object? title = null,Object? averageScore = null,Object? bannerImage = null,Object? chapters = null,Object? countryOfOrigin = null,Object? coverImage = null,Object? description = null,Object? endDate = null,Object? startDate = null,Object? genres = null,Object? format = null,Object? isAdult = null,Object? popularity = null,Object? meanScore = null,Object? status = null,Object? isFavourite = null,}) {
|
||||
return _then(_ShikimoriMangaModel(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as int,idMal: null == idMal ? _self.idMal : idMal // ignore: cast_nullable_to_non_nullable
|
||||
as int,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||
as Title,averageScore: null == averageScore ? _self.averageScore : averageScore // ignore: cast_nullable_to_non_nullable
|
||||
as int,bannerImage: null == bannerImage ? _self.bannerImage : bannerImage // ignore: cast_nullable_to_non_nullable
|
||||
as String,chapters: null == chapters ? _self.chapters : chapters // ignore: cast_nullable_to_non_nullable
|
||||
as int,countryOfOrigin: null == countryOfOrigin ? _self.countryOfOrigin : countryOfOrigin // ignore: cast_nullable_to_non_nullable
|
||||
as String,coverImage: null == coverImage ? _self.coverImage : coverImage // ignore: cast_nullable_to_non_nullable
|
||||
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||
as String,endDate: null == endDate ? _self.endDate : endDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,startDate: null == startDate ? _self.startDate : startDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,genres: null == genres ? _self._genres : genres // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,format: null == format ? _self.format : format // ignore: cast_nullable_to_non_nullable
|
||||
as String,isAdult: null == isAdult ? _self.isAdult : isAdult // ignore: cast_nullable_to_non_nullable
|
||||
as bool,popularity: null == popularity ? _self.popularity : popularity // ignore: cast_nullable_to_non_nullable
|
||||
as int,meanScore: null == meanScore ? _self.meanScore : meanScore // ignore: cast_nullable_to_non_nullable
|
||||
as int,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||
as String,isFavourite: null == isFavourite ? _self.isFavourite : isFavourite // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
53
lib/data/models/shikimori/media/shikimori_manga_model.g.dart
Normal file
53
lib/data/models/shikimori/media/shikimori_manga_model.g.dart
Normal file
@@ -0,0 +1,53 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'shikimori_manga_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_ShikimoriMangaModel _$ShikimoriMangaModelFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _ShikimoriMangaModel(
|
||||
id: (json['id'] as num).toInt(),
|
||||
idMal: (json['idMal'] as num).toInt(),
|
||||
title: const TitleConverter().fromJson(json['title'] as Map<String, dynamic>),
|
||||
averageScore: (json['averageScore'] as num).toInt(),
|
||||
bannerImage: json['bannerImage'] as String,
|
||||
chapters: (json['chapters'] as num).toInt(),
|
||||
countryOfOrigin: json['countryOfOrigin'] as String,
|
||||
coverImage: json['coverImage'] as String,
|
||||
description: json['description'] as String,
|
||||
endDate: json['endDate'] as String,
|
||||
startDate: json['startDate'] as String,
|
||||
genres: (json['genres'] as List<dynamic>).map((e) => e as String).toList(),
|
||||
format: json['format'] as String,
|
||||
isAdult: json['isAdult'] as bool,
|
||||
popularity: (json['popularity'] as num).toInt(),
|
||||
meanScore: (json['meanScore'] as num).toInt(),
|
||||
status: json['status'] as String,
|
||||
isFavourite: json['isFavourite'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ShikimoriMangaModelToJson(
|
||||
_ShikimoriMangaModel instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'idMal': instance.idMal,
|
||||
'title': const TitleConverter().toJson(instance.title),
|
||||
'averageScore': instance.averageScore,
|
||||
'bannerImage': instance.bannerImage,
|
||||
'chapters': instance.chapters,
|
||||
'countryOfOrigin': instance.countryOfOrigin,
|
||||
'coverImage': instance.coverImage,
|
||||
'description': instance.description,
|
||||
'endDate': instance.endDate,
|
||||
'startDate': instance.startDate,
|
||||
'genres': instance.genres,
|
||||
'format': instance.format,
|
||||
'isAdult': instance.isAdult,
|
||||
'popularity': instance.popularity,
|
||||
'meanScore': instance.meanScore,
|
||||
'status': instance.status,
|
||||
'isFavourite': instance.isFavourite,
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
// External dependencies
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
// Internal dependencies
|
||||
import 'package:unyo/domain/entities/media/media_character.dart';
|
||||
|
||||
part 'shikimori_media_character.freezed.dart';
|
||||
part 'shikimori_media_character.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ShikimoriMediaCharacterModel
|
||||
with _$ShikimoriMediaCharacterModel
|
||||
implements MediaCharacter {
|
||||
const factory ShikimoriMediaCharacterModel({
|
||||
required int id,
|
||||
required String image,
|
||||
required String name,
|
||||
required String gender,
|
||||
required String description,
|
||||
required String dateOfBirth,
|
||||
required int age,
|
||||
}) = _ShikimoriMediaCharacterModel;
|
||||
|
||||
factory ShikimoriMediaCharacterModel.empty() =>
|
||||
const ShikimoriMediaCharacterModel(
|
||||
id: -1,
|
||||
image: '',
|
||||
name: '',
|
||||
gender: '',
|
||||
description: '',
|
||||
dateOfBirth: '',
|
||||
age: 0,
|
||||
);
|
||||
|
||||
factory ShikimoriMediaCharacterModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$ShikimoriMediaCharacterModelFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$ShikimoriMediaCharacterModelToJson(this as _ShikimoriMediaCharacterModel);
|
||||
|
||||
// factory ShikimoriMediaCharacterModel.fromCharacterRole(
|
||||
// ShikimoriAnimeDetailsGraphqlAnimeCharacterRoles role,) {
|
||||
// return ShikimoriMediaCharacterModel(
|
||||
// id: int.parse(role.character.id),
|
||||
// image: role.character.poster.originalUrl,
|
||||
// name: role.character.name,
|
||||
// gender: '',
|
||||
// description: '',
|
||||
// dateOfBirth: '',
|
||||
// age: 0,
|
||||
// );
|
||||
// }
|
||||
|
||||
// factory ShikimoriMediaCharacterModel.fromMangaCharacterRole(
|
||||
// ShikimoriMangaDetailsGraphqlMangaCharacterRoles role,) {
|
||||
// return ShikimoriMediaCharacterModel(
|
||||
// id: int.parse(role.character.id),
|
||||
// image: role.character.poster.originalUrl,
|
||||
// name: role.character.name,
|
||||
// gender: '',
|
||||
// description: '',
|
||||
// dateOfBirth: '',
|
||||
// age: 0,
|
||||
// );
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'shikimori_media_character.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ShikimoriMediaCharacterModel {
|
||||
|
||||
int get id; String get image; String get name; String get gender; String get description; String get dateOfBirth; int get age;
|
||||
/// Create a copy of ShikimoriMediaCharacterModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ShikimoriMediaCharacterModelCopyWith<ShikimoriMediaCharacterModel> get copyWith => _$ShikimoriMediaCharacterModelCopyWithImpl<ShikimoriMediaCharacterModel>(this as ShikimoriMediaCharacterModel, _$identity);
|
||||
|
||||
/// Serializes this ShikimoriMediaCharacterModel to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ShikimoriMediaCharacterModel&&(identical(other.id, id) || other.id == id)&&(identical(other.image, image) || other.image == image)&&(identical(other.name, name) || other.name == name)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.description, description) || other.description == description)&&(identical(other.dateOfBirth, dateOfBirth) || other.dateOfBirth == dateOfBirth)&&(identical(other.age, age) || other.age == age));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,image,name,gender,description,dateOfBirth,age);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ShikimoriMediaCharacterModelCopyWith<$Res> {
|
||||
factory $ShikimoriMediaCharacterModelCopyWith(ShikimoriMediaCharacterModel value, $Res Function(ShikimoriMediaCharacterModel) _then) = _$ShikimoriMediaCharacterModelCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
int id, String image, String name, String gender, String description, String dateOfBirth, int age
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ShikimoriMediaCharacterModelCopyWithImpl<$Res>
|
||||
implements $ShikimoriMediaCharacterModelCopyWith<$Res> {
|
||||
_$ShikimoriMediaCharacterModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ShikimoriMediaCharacterModel _self;
|
||||
final $Res Function(ShikimoriMediaCharacterModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriMediaCharacterModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? image = null,Object? name = null,Object? gender = null,Object? description = null,Object? dateOfBirth = null,Object? age = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as int,image: null == image ? _self.image : image // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String,gender: null == gender ? _self.gender : gender // ignore: cast_nullable_to_non_nullable
|
||||
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||
as String,dateOfBirth: null == dateOfBirth ? _self.dateOfBirth : dateOfBirth // ignore: cast_nullable_to_non_nullable
|
||||
as String,age: null == age ? _self.age : age // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ShikimoriMediaCharacterModel].
|
||||
extension ShikimoriMediaCharacterModelPatterns on ShikimoriMediaCharacterModel {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ShikimoriMediaCharacterModel value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMediaCharacterModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ShikimoriMediaCharacterModel value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMediaCharacterModel():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ShikimoriMediaCharacterModel value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMediaCharacterModel() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int id, String image, String name, String gender, String description, String dateOfBirth, int age)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMediaCharacterModel() when $default != null:
|
||||
return $default(_that.id,_that.image,_that.name,_that.gender,_that.description,_that.dateOfBirth,_that.age);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int id, String image, String name, String gender, String description, String dateOfBirth, int age) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMediaCharacterModel():
|
||||
return $default(_that.id,_that.image,_that.name,_that.gender,_that.description,_that.dateOfBirth,_that.age);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int id, String image, String name, String gender, String description, String dateOfBirth, int age)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ShikimoriMediaCharacterModel() when $default != null:
|
||||
return $default(_that.id,_that.image,_that.name,_that.gender,_that.description,_that.dateOfBirth,_that.age);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _ShikimoriMediaCharacterModel implements ShikimoriMediaCharacterModel {
|
||||
const _ShikimoriMediaCharacterModel({required this.id, required this.image, required this.name, required this.gender, required this.description, required this.dateOfBirth, required this.age});
|
||||
factory _ShikimoriMediaCharacterModel.fromJson(Map<String, dynamic> json) => _$ShikimoriMediaCharacterModelFromJson(json);
|
||||
|
||||
@override final int id;
|
||||
@override final String image;
|
||||
@override final String name;
|
||||
@override final String gender;
|
||||
@override final String description;
|
||||
@override final String dateOfBirth;
|
||||
@override final int age;
|
||||
|
||||
/// Create a copy of ShikimoriMediaCharacterModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ShikimoriMediaCharacterModelCopyWith<_ShikimoriMediaCharacterModel> get copyWith => __$ShikimoriMediaCharacterModelCopyWithImpl<_ShikimoriMediaCharacterModel>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$ShikimoriMediaCharacterModelToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ShikimoriMediaCharacterModel&&(identical(other.id, id) || other.id == id)&&(identical(other.image, image) || other.image == image)&&(identical(other.name, name) || other.name == name)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.description, description) || other.description == description)&&(identical(other.dateOfBirth, dateOfBirth) || other.dateOfBirth == dateOfBirth)&&(identical(other.age, age) || other.age == age));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,image,name,gender,description,dateOfBirth,age);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ShikimoriMediaCharacterModelCopyWith<$Res> implements $ShikimoriMediaCharacterModelCopyWith<$Res> {
|
||||
factory _$ShikimoriMediaCharacterModelCopyWith(_ShikimoriMediaCharacterModel value, $Res Function(_ShikimoriMediaCharacterModel) _then) = __$ShikimoriMediaCharacterModelCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
int id, String image, String name, String gender, String description, String dateOfBirth, int age
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ShikimoriMediaCharacterModelCopyWithImpl<$Res>
|
||||
implements _$ShikimoriMediaCharacterModelCopyWith<$Res> {
|
||||
__$ShikimoriMediaCharacterModelCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ShikimoriMediaCharacterModel _self;
|
||||
final $Res Function(_ShikimoriMediaCharacterModel) _then;
|
||||
|
||||
/// Create a copy of ShikimoriMediaCharacterModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? image = null,Object? name = null,Object? gender = null,Object? description = null,Object? dateOfBirth = null,Object? age = null,}) {
|
||||
return _then(_ShikimoriMediaCharacterModel(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as int,image: null == image ? _self.image : image // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String,gender: null == gender ? _self.gender : gender // ignore: cast_nullable_to_non_nullable
|
||||
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||
as String,dateOfBirth: null == dateOfBirth ? _self.dateOfBirth : dateOfBirth // ignore: cast_nullable_to_non_nullable
|
||||
as String,age: null == age ? _self.age : age // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -0,0 +1,31 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'shikimori_media_character.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_ShikimoriMediaCharacterModel _$ShikimoriMediaCharacterModelFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _ShikimoriMediaCharacterModel(
|
||||
id: (json['id'] as num).toInt(),
|
||||
image: json['image'] as String,
|
||||
name: json['name'] as String,
|
||||
gender: json['gender'] as String,
|
||||
description: json['description'] as String,
|
||||
dateOfBirth: json['dateOfBirth'] as String,
|
||||
age: (json['age'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ShikimoriMediaCharacterModelToJson(
|
||||
_ShikimoriMediaCharacterModel instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'image': instance.image,
|
||||
'name': instance.name,
|
||||
'gender': instance.gender,
|
||||
'description': instance.description,
|
||||
'dateOfBirth': instance.dateOfBirth,
|
||||
'age': instance.age,
|
||||
};
|
||||
@@ -19,9 +19,9 @@ import 'package:unyo/core/services/api/graphql/queries/anilist_queries.dart' as
|
||||
import 'package:unyo/core/services/api/dto/anilist/media_collection_recently_released_graphql_entity.dart';
|
||||
import 'package:unyo/core/services/api/graphql/graphql_response.dart';
|
||||
import 'package:unyo/core/services/api/graphql/graphql_service.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_anime_details.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_anime_model.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_anime_details.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_anime_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/repositories/repository_mixin.dart';
|
||||
import 'package:unyo/domain/entities/media/anime.dart';
|
||||
import 'package:unyo/domain/entities/media/anime_details.dart';
|
||||
|
||||
495
lib/data/repositories/anime_repository_shikimori.dart
Normal file
495
lib/data/repositories/anime_repository_shikimori.dart
Normal file
@@ -0,0 +1,495 @@
|
||||
// External dependencies
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
// Internal dependencies
|
||||
import 'package:unyo/config/config.dart' as config;
|
||||
import 'package:unyo/core/di/locator.dart';
|
||||
import 'package:unyo/core/services/api/graphql/graphql_service.dart';
|
||||
import 'package:unyo/core/services/api/graphql/queries/shikimori_queries.dart' as shikimori_queries;
|
||||
import 'package:unyo/data/repositories/repository_mixin.dart';
|
||||
import 'package:unyo/domain/entities/media/anime.dart';
|
||||
import 'package:unyo/domain/entities/media/anime_details.dart';
|
||||
import 'package:unyo/domain/entities/list/media_list_entry.dart';
|
||||
import 'package:unyo/domain/entities/user/user.dart';
|
||||
import 'package:unyo/domain/repositories/anime_repository.dart';
|
||||
|
||||
class AnimeRepositoryShikimori with RepositoryMixin implements AnimeRepository {
|
||||
final GraphQLService _shikimoriGraphQLService = sl<GraphQLService>(
|
||||
instanceName: config.shikimoriGraphQlService,
|
||||
);
|
||||
final Logger _logger = sl<Logger>();
|
||||
|
||||
@override
|
||||
Future<(bool, AnimeDetails)> getAnimeDetails(Anime selectedAnime, User loggedUser) {
|
||||
// TODO: implement getAnimeDetails
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, List<Anime>>> getCalendarReleases(int page, User loggedUser) {
|
||||
// TODO: implement getCalendarReleases
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
// Daqui
|
||||
@override
|
||||
Future<(bool, List<Anime>)> getPopularAnimes(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getPopularAnimes
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<(bool, List<Anime>)> getRecentlyCompletedAnimes(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getRecentlyCompletedAnimes
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<(bool, List<Anime>)> getRecentlyReleasedAnimes(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getRecentlyReleasedAnimes
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<(bool, List<Anime>)> getTrendingAnimes(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getTrendingAnimes
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<(bool, List<Anime>)> getUpcomingAnimes(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getUpcomingAnimes
|
||||
throw UnimplementedError();
|
||||
}
|
||||
// Ate aqui
|
||||
@override
|
||||
Future<Map<String, (bool, List<String>)>> getUserAnimeAdvancedSearchFilters() {
|
||||
// TODO: implement getUserAnimeAdvancedSearchFilters
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Anime>> performAnimeAdvancedSearch(String query, List<String> selectedGenres, String? selectedSeason, String? selectedFormat, int? selectedYear, String? selectedAiringStatus, String sort, int page, User loggedUser) {
|
||||
// TODO: implement performAnimeAdvancedSearch
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
// @override
|
||||
// Future<(bool, List<Anime>)> getPopularAnimes(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori popular anime");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriAnimeListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriAnimeListQuery,
|
||||
// fromJson: ShikimoriAnimeListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "popularity",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final animes = _processPaginatedResponse(response.data.animes, 30);
|
||||
// return (animes.$1, animes.$2.map((e) => ShikimoriAnimeModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<(bool, List<Anime>)> getTrendingAnimes(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori trending anime");
|
||||
// // Shikimori doesn't have a native "trending" concept; use popularity as closest equivalent
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriAnimeListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriAnimeListQuery,
|
||||
// fromJson: ShikimoriAnimeListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "popularity",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final animes = _processPaginatedResponse(response.data.animes, 30);
|
||||
// return (animes.$1, animes.$2.map((e) => ShikimoriAnimeModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<(bool, List<Anime>)> getRecentlyReleasedAnimes(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori recently released anime");
|
||||
// final now = DateTime.now();
|
||||
// final currentSeason = _getCurrentSeason(now);
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriAnimeListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriAnimeListQuery,
|
||||
// fromJson: ShikimoriAnimeListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "aired_on",
|
||||
// "status": "released",
|
||||
// "season": currentSeason,
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final animes = _processPaginatedResponse(response.data.animes, 30);
|
||||
// return (animes.$1, animes.$2.map((e) => ShikimoriAnimeModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<(bool, List<Anime>)> getRecentlyCompletedAnimes(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori recently completed anime");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriAnimeListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriAnimeListQuery,
|
||||
// fromJson: ShikimoriAnimeListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "aired_on",
|
||||
// "status": "released",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final animes = _processPaginatedResponse(response.data.animes, 30);
|
||||
// return (animes.$1, animes.$2.map((e) => ShikimoriAnimeModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<(bool, List<Anime>)> getUpcomingAnimes(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori upcoming anime");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriAnimeListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriAnimeListQuery,
|
||||
// fromJson: ShikimoriAnimeListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "popularity",
|
||||
// "status": "anons",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final animes = _processPaginatedResponse(response.data.animes, 30);
|
||||
// return (animes.$1, animes.$2.map((e) => ShikimoriAnimeModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<Map<String, List<Anime>>> getCalendarReleases(int page, User loggedUser) async {
|
||||
// _logger.i("Fetching Shikimori calendar releases");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriAnimeListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriAnimeListQuery,
|
||||
// fromJson: ShikimoriAnimeListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 50,
|
||||
// "order": "ranked",
|
||||
// "status": "ongoing",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final localeTag = loggedUser.settings.language;
|
||||
// final calendarReleases = <String, List<Anime>>{};
|
||||
// for (final entry in response.data.animes) {
|
||||
// final anime = ShikimoriAnimeModel.fromListEntry(entry);
|
||||
// if (anime.isAdult && !loggedUser.settings.enableNsfwContent) continue;
|
||||
// if (entry.nextEpisodeAt != null) {
|
||||
// final episodeRelease = DateTime.parse(entry.nextEpisodeAt.toString());
|
||||
// final dateKey = DateFormat('EEEE, MMMM d, y', localeTag).format(episodeRelease);
|
||||
// if (!calendarReleases.containsKey(dateKey)) {
|
||||
// calendarReleases[dateKey] = [anime];
|
||||
// } else {
|
||||
// calendarReleases[dateKey]!.add(anime);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // Sort each list by airing time
|
||||
// calendarReleases.forEach((date, animeList) {
|
||||
// animeList.sort((a, b) => a.nextAiringEpisode.airingAt.compareTo(b.nextAiringEpisode.airingAt));
|
||||
// });
|
||||
// // Sort map entries by date
|
||||
// final sortedEntries = calendarReleases.entries.toList()
|
||||
// ..sort((a, b) {
|
||||
// final dateA = DateFormat('EEEE, MMMM d, y', localeTag).parse(a.key);
|
||||
// final dateB = DateFormat('EEEE, MMMM d, y', localeTag).parse(b.key);
|
||||
// return dateA.millisecondsSinceEpoch.compareTo(dateB.millisecondsSinceEpoch);
|
||||
// });
|
||||
// return Map.fromEntries(sortedEntries);
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<(bool, AnimeDetails)> getAnimeDetails(Anime selectedAnime, User loggedUser) async {
|
||||
// _logger.i("Fetching Anime Details from Shikimori for ${selectedAnime.title.userPreferred}");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriAnimeDetailsGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriAnimeDetailsQuery,
|
||||
// fromJson: ShikimoriAnimeDetailsGraphqlEntity.fromJson,
|
||||
// variables: {"ids": selectedAnime.id.toString()},
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// if (response.data.anime.isEmpty) {
|
||||
// return (false, AnimeDetailsModel.empty());
|
||||
// }
|
||||
// final animeDetails = ShikimoriAnimeDetailsModel.fromDetailsEntry(response.data.anime.first);
|
||||
// return (true, animeDetails);
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<Map<String, (bool, List<String>)>> getUserAnimeAdvancedSearchFilters() async {
|
||||
// _logger.i("Fetching Shikimori anime advanced search filters");
|
||||
// final filters = <String, (bool, List<String>)>{};
|
||||
// // Fetch genres from API
|
||||
// final genresResponse = await _shikimoriGraphQLService.query<ShikimoriGenresGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriGenresListQuery,
|
||||
// fromJson: ShikimoriGenresGraphqlEntity.fromJson,
|
||||
// variables: {"entryType": "Anime"},
|
||||
// );
|
||||
// throwIfGraphQlError(genresResponse);
|
||||
// final genreNames = genresResponse.data.genres.map((g) => g.name).toList();
|
||||
// filters.addAll({
|
||||
// 'genres': (true, TextUtils.capitalizeList(genreNames)),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'seasons': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriSeasonFilters.values.map((e) => e.name).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'formats': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriFormatFilters.values.map((e) => e.name.replaceAll('_', ' ')).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'airingStatuses': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriAiringStatusFilters.values.map((e) => e.name.replaceAll('_', ' ')).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'years': (
|
||||
// true,
|
||||
// List<String>.generate(
|
||||
// DateTime.now().year - 1939,
|
||||
// (index) => (1940 + index).toString(),
|
||||
// ).reversed.toList(),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'sortOptions': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriSortOptions.values.map((e) => e.name.replaceAll('_', ' ')).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'sortOrders': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriSortOrder.values.map((e) => e.name).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// return filters;
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<List<Anime>> performAnimeAdvancedSearch(
|
||||
// String query,
|
||||
// List<String> selectedGenres,
|
||||
// String? selectedSeason,
|
||||
// String? selectedFormat,
|
||||
// int? selectedYear,
|
||||
// String? selectedAiringStatus,
|
||||
// String sort,
|
||||
// int page,
|
||||
// User loggedUser,
|
||||
// ) async {
|
||||
// _logger.i("Performing Shikimori anime advanced search");
|
||||
// // Map genre names to IDs if needed - for now, Shikimori search uses genre IDs
|
||||
// // But since we don't have ID mapping easily, we'll use genre names
|
||||
// // Actually Shikimori genre filter accepts IDs, not names
|
||||
// // For simplicity, we'll skip genre filtering in search or map common ones
|
||||
// final genreIds = await _mapGenreNamesToIds(selectedGenres, "Anime");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriAnimeListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriAnimeListQuery,
|
||||
// fromJson: ShikimoriAnimeListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 50,
|
||||
// "order": _mapSortToShikimori(sort),
|
||||
// if (query.isNotEmpty) "search": query,
|
||||
// if (genreIds.isNotEmpty) "genre": genreIds.join(','),
|
||||
// if (selectedSeason != null && selectedSeason.isNotEmpty) "season": selectedSeason.toLowerCase(),
|
||||
// if (selectedYear != null) "season": "$selectedYear",
|
||||
// if (selectedAiringStatus != null && selectedAiringStatus.isNotEmpty)
|
||||
// "status": _mapAiringStatusToShikimori(selectedAiringStatus),
|
||||
// if (selectedFormat != null && selectedFormat.isNotEmpty)
|
||||
// "kind": _mapFormatToShikimoriKind(selectedFormat),
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// return response.data.animes.map((e) => ShikimoriAnimeModel.fromListEntry(e)).toList();
|
||||
// }
|
||||
|
||||
@override
|
||||
Future<List<String>> getMediaCoverImages(User loggedUser, {bool ignoreCache = false}) async {
|
||||
_logger.i("Fetching Media Cover Images from Shikimori");
|
||||
final (hasNext, animes) = await getPopularAnimes(1, loggedUser, ignoreCache: ignoreCache);
|
||||
return animes.map((anime) => anime.coverImage).where((coverImage) => coverImage != "").shuffled(Random()).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MediaListEntry> updateMediaListEntry(MediaListEntry newMediaListEntry, Anime selectedAnime, User loggedUser) async {
|
||||
_logger.i("Updating Media List Entry to $newMediaListEntry on Shikimori");
|
||||
// Metadata-only scope: return empty
|
||||
return MediaListEntryModel.empty();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MediaListEntry> getMediaListEntry(Anime selectedAnime, User loggedUser, {bool ignoreCache = false}) async {
|
||||
_logger.i("Fetching User Media List Entry from Shikimori for ${selectedAnime.title.userPreferred}");
|
||||
// Metadata-only scope: return empty
|
||||
return MediaListEntryModel.empty();
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
// (bool, List<ShikimoriAnimeListGraphqlAnimes>) _processPaginatedResponse(
|
||||
// List<ShikimoriAnimeListGraphqlAnimes> results,
|
||||
// int limit,
|
||||
// ) {
|
||||
// final hasNextPage = results.length > limit;
|
||||
// final items = hasNextPage ? results.take(limit).toList() : results;
|
||||
// return (hasNextPage, items);
|
||||
// }
|
||||
|
||||
String _getCurrentSeason(DateTime date) {
|
||||
final month = date.month;
|
||||
String season;
|
||||
if (month >= 1 && month <= 3) {
|
||||
season = 'winter';
|
||||
} else if (month >= 4 && month <= 6) {
|
||||
season = 'spring';
|
||||
} else if (month >= 7 && month <= 9) {
|
||||
season = 'summer';
|
||||
} else {
|
||||
season = 'fall';
|
||||
}
|
||||
return "${season}_${date.year}";
|
||||
}
|
||||
|
||||
// Future<List<String>> _mapGenreNamesToIds(List<String> genreNames, String entryType) async {
|
||||
// if (genreNames.isEmpty) return [];
|
||||
// final genresResponse = await _shikimoriGraphQLService.query<ShikimoriGenresGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriGenresListQuery,
|
||||
// fromJson: ShikimoriGenresGraphqlEntity.fromJson,
|
||||
// variables: {"entryType": entryType},
|
||||
// );
|
||||
// throwIfGraphQlError(genresResponse);
|
||||
// final genreMap = <String, String>{};
|
||||
// for (final genre in genresResponse.data.genres) {
|
||||
// genreMap[genre.name.toLowerCase()] = genre.id;
|
||||
// }
|
||||
// return genreNames
|
||||
// .map((name) => genreMap[name.toLowerCase()])
|
||||
// .whereType<String>()
|
||||
// .toList();
|
||||
// }
|
||||
|
||||
String _mapSortToShikimori(String sort) {
|
||||
// sort comes as "popularity_desc" or "score_desc" etc.
|
||||
final parts = sort.toLowerCase().split('_');
|
||||
if (parts.length < 2) return 'popularity';
|
||||
final field = parts.first;
|
||||
switch (field) {
|
||||
case 'popularity':
|
||||
return 'popularity';
|
||||
case 'score':
|
||||
return 'ranked';
|
||||
case 'startdate':
|
||||
case 'start_date':
|
||||
return 'aired_on';
|
||||
case 'enddate':
|
||||
case 'end_date':
|
||||
return 'aired_on';
|
||||
case 'title':
|
||||
return 'name';
|
||||
case 'episodes':
|
||||
return 'episodes';
|
||||
case 'status':
|
||||
return 'status';
|
||||
case 'trending':
|
||||
return 'popularity';
|
||||
default:
|
||||
return 'popularity';
|
||||
}
|
||||
}
|
||||
|
||||
String _mapAiringStatusToShikimori(String status) {
|
||||
switch (status.toLowerCase().replaceAll(' ', '_')) {
|
||||
case 'releasing':
|
||||
return 'ongoing';
|
||||
case 'finished':
|
||||
return 'released';
|
||||
case 'not_yet_released':
|
||||
return 'anons';
|
||||
case 'cancelled':
|
||||
return 'released'; // Shikimori doesn't have cancelled
|
||||
default:
|
||||
return status.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
String _mapFormatToShikimoriKind(String format) {
|
||||
switch (format.toLowerCase().replaceAll(' ', '_')) {
|
||||
case 'tv':
|
||||
return 'tv';
|
||||
case 'tv_short':
|
||||
return 'tv_special';
|
||||
case 'movie':
|
||||
return 'movie';
|
||||
case 'special':
|
||||
return 'special';
|
||||
case 'ova':
|
||||
return 'ova';
|
||||
case 'ona':
|
||||
return 'ona';
|
||||
case 'music':
|
||||
return 'music';
|
||||
default:
|
||||
return format.toLowerCase().replaceAll(' ', '_');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ShikimoriSeasonFilters { winter, spring, summer, fall }
|
||||
|
||||
enum ShikimoriFormatFilters { tv, movie, tv_special, special, ova, ona, music }
|
||||
|
||||
enum ShikimoriAiringStatusFilters { ongoing, released, anons }
|
||||
|
||||
enum ShikimoriSortOptions {
|
||||
popularity,
|
||||
ranked,
|
||||
name,
|
||||
aired_on,
|
||||
episodes,
|
||||
status,
|
||||
}
|
||||
|
||||
enum ShikimoriSortOrder { asc, desc }
|
||||
@@ -14,9 +14,9 @@ import 'package:unyo/core/services/api/dto/anilist/media_details_graphql_entity.
|
||||
import 'package:unyo/core/services/api/dto/anilist/media_details_media_list_entry_entity.dart';
|
||||
import 'package:unyo/core/services/api/graphql/graphql_response.dart';
|
||||
import 'package:unyo/core/services/api/graphql/graphql_service.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_manga_details.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_manga_model.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_manga_details.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_manga_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/repositories/repository_mixin.dart';
|
||||
import 'package:unyo/domain/entities/media/manga.dart';
|
||||
import 'package:unyo/domain/entities/media/manga_details.dart';
|
||||
|
||||
349
lib/data/repositories/manga_repository_shikimori.dart
Normal file
349
lib/data/repositories/manga_repository_shikimori.dart
Normal file
@@ -0,0 +1,349 @@
|
||||
// External dependencies
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
// Internal dependencies
|
||||
import 'package:unyo/config/config.dart' as config;
|
||||
import 'package:unyo/core/di/locator.dart';
|
||||
import 'package:unyo/core/services/api/graphql/graphql_service.dart';
|
||||
import 'package:unyo/core/services/api/graphql/queries/shikimori_queries.dart' as shikimori_queries;
|
||||
import 'package:unyo/data/repositories/repository_mixin.dart';
|
||||
import 'package:unyo/domain/entities/media/manga.dart';
|
||||
import 'package:unyo/domain/entities/media/manga_details.dart';
|
||||
import 'package:unyo/domain/entities/user/user.dart';
|
||||
import 'package:unyo/domain/repositories/manga_repository.dart';
|
||||
|
||||
class MangaRepositoryShikimori with RepositoryMixin implements MangaRepository {
|
||||
final GraphQLService _shikimoriGraphQLService = sl<GraphQLService>(
|
||||
instanceName: config.shikimoriGraphQlService,
|
||||
);
|
||||
final Logger _logger = sl<Logger>();
|
||||
|
||||
@override
|
||||
Future<(bool, MangaDetails)> getMangaDetails(Manga selectedManga, User loggedUser) {
|
||||
// TODO: implement getMangaDetails
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<(bool, List<Manga>)> getPopularMangas(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getPopularMangas
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<(bool, List<Manga>)> getRecentlyCompletedMangas(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getRecentlyCompletedMangas
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<(bool, List<Manga>)> getTrendingMangas(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getTrendingMangas
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<(bool, List<Manga>)> getUpcomingMangas(int page, User loggedUser, {bool ignoreCache = false}) {
|
||||
// TODO: implement getUpcomingMangas
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, (bool, List<String>)>> getUserMangaAdvancedSearchFilters() {
|
||||
// TODO: implement getUserMangaAdvancedSearchFilters
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Manga>> performMangaAdvancedSearch(String query, List<String> selectedGenres, String? selectedFormat, String? selectedCountry, String? selectedAiringStatus, String sort, int page, User loggedUser) {
|
||||
// TODO: implement performMangaAdvancedSearch
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
// @override
|
||||
// Future<(bool, List<Manga>)> getPopularMangas(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori popular manga");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriMangaListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriMangaListQuery,
|
||||
// fromJson: ShikimoriMangaListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "popularity",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final mangas = _processPaginatedResponse(response.data.mangas, 30);
|
||||
// return (mangas.$1, mangas.$2.map((e) => ShikimoriMangaModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<(bool, List<Manga>)> getTrendingMangas(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori trending manga");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriMangaListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriMangaListQuery,
|
||||
// fromJson: ShikimoriMangaListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "popularity",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final mangas = _processPaginatedResponse(response.data.mangas, 30);
|
||||
// return (mangas.$1, mangas.$2.map((e) => ShikimoriMangaModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<(bool, List<Manga>)> getRecentlyCompletedMangas(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori recently completed manga");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriMangaListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriMangaListQuery,
|
||||
// fromJson: ShikimoriMangaListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "aired_on",
|
||||
// "status": "released",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final mangas = _processPaginatedResponse(response.data.mangas, 30);
|
||||
// return (mangas.$1, mangas.$2.map((e) => ShikimoriMangaModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<(bool, List<Manga>)> getUpcomingMangas(int page, User loggedUser, {bool ignoreCache = false}) async {
|
||||
// _logger.i("Fetching Shikimori upcoming manga");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriMangaListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriMangaListQuery,
|
||||
// fromJson: ShikimoriMangaListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 31,
|
||||
// "order": "popularity",
|
||||
// "status": "anons",
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// ignoreCache: ignoreCache,
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// final mangas = _processPaginatedResponse(response.data.mangas, 30);
|
||||
// return (mangas.$1, mangas.$2.map((e) => ShikimoriMangaModel.fromListEntry(e)).toList());
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<(bool, MangaDetails)> getMangaDetails(Manga selectedManga, User loggedUser) async {
|
||||
// _logger.i("Fetching Manga Details from Shikimori for ${selectedManga.title.userPreferred}");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriMangaDetailsGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriMangaDetailsQuery,
|
||||
// fromJson: ShikimoriMangaDetailsGraphqlEntity.fromJson,
|
||||
// variables: {"ids": selectedManga.id.toString()},
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// if (response.data.manga.isEmpty) {
|
||||
// return (false, MangaDetailsModel.empty());
|
||||
// }
|
||||
// final mangaDetails = ShikimoriMangaDetailsModel.fromDetailsEntry(response.data.manga.first);
|
||||
// return (true, mangaDetails);
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<Map<String, (bool, List<String>)>> getUserMangaAdvancedSearchFilters() async {
|
||||
// _logger.i("Fetching Shikimori manga advanced search filters");
|
||||
// final filters = <String, (bool, List<String>)>{};
|
||||
// final genresResponse = await _shikimoriGraphQLService.query<ShikimoriGenresGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriGenresListQuery,
|
||||
// fromJson: ShikimoriGenresGraphqlEntity.fromJson,
|
||||
// variables: {"entryType": "Manga"},
|
||||
// );
|
||||
// throwIfGraphQlError(genresResponse);
|
||||
// final genreNames = genresResponse.data.genres.map((g) => g.name).toList();
|
||||
// filters.addAll({
|
||||
// 'genres': (true, TextUtils.capitalizeList(genreNames)),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'formats': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriMangaFormatFilters.values.map((e) => e.name.replaceAll('_', ' ')).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'airingStatuses': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriMangaStatusFilters.values.map((e) => e.name.replaceAll('_', ' ')).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'years': (
|
||||
// true,
|
||||
// List<String>.generate(
|
||||
// DateTime.now().year - 1939,
|
||||
// (index) => (1940 + index).toString(),
|
||||
// ).reversed.toList(),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'sortOptions': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriMangaSortOptions.values.map((e) => e.name.replaceAll('_', ' ')).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// filters.addAll({
|
||||
// 'sortOrders': (
|
||||
// true,
|
||||
// TextUtils.capitalizeList(
|
||||
// ShikimoriMangaSortOrder.values.map((e) => e.name).toList(),
|
||||
// ),
|
||||
// ),
|
||||
// });
|
||||
// return filters;
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<List<Manga>> performMangaAdvancedSearch(
|
||||
// String query,
|
||||
// List<String> selectedGenres,
|
||||
// String? selectedFormat,
|
||||
// String? selectedCountry,
|
||||
// String? selectedAiringStatus,
|
||||
// String sort,
|
||||
// int page,
|
||||
// User loggedUser,
|
||||
// ) async {
|
||||
// _logger.i("Performing Shikimori manga advanced search");
|
||||
// final genreIds = await _mapGenreNamesToIds(selectedGenres, "Manga");
|
||||
// final response = await _shikimoriGraphQLService.query<ShikimoriMangaListGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriMangaListQuery,
|
||||
// fromJson: ShikimoriMangaListGraphqlEntity.fromJson,
|
||||
// variables: {
|
||||
// "page": page,
|
||||
// "limit": 50,
|
||||
// "order": _mapSortToShikimori(sort),
|
||||
// if (query.isNotEmpty) "search": query,
|
||||
// if (genreIds.isNotEmpty) "genre": genreIds.join(','),
|
||||
// if (selectedAiringStatus != null && selectedAiringStatus.isNotEmpty)
|
||||
// "status": _mapAiringStatusToShikimori(selectedAiringStatus),
|
||||
// if (selectedFormat != null && selectedFormat.isNotEmpty)
|
||||
// "kind": _mapFormatToShikimoriKind(selectedFormat),
|
||||
// "censored": loggedUser.settings.enableNsfwContent ? null : false,
|
||||
// },
|
||||
// );
|
||||
// throwIfGraphQlError(response);
|
||||
// return response.data.mangas.map((e) => ShikimoriMangaModel.fromListEntry(e)).toList();
|
||||
// }
|
||||
|
||||
@override
|
||||
Future<List<String>> getMediaCoverImages(User loggedUser, {bool ignoreCache = false}) async {
|
||||
_logger.i("Fetching Media Cover Images from Shikimori");
|
||||
final (hasNext, mangas) = await getPopularMangas(1, loggedUser, ignoreCache: ignoreCache);
|
||||
return mangas.map((manga) => manga.coverImage).where((coverImage) => coverImage != "").shuffled(Random()).toList();
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
// (bool, List<ShikimoriMangaListGraphqlMangas>) _processPaginatedResponse(
|
||||
// List<ShikimoriMangaListGraphqlMangas> results,
|
||||
// int limit,
|
||||
// ) {
|
||||
// final hasNextPage = results.length > limit;
|
||||
// final items = hasNextPage ? results.take(limit).toList() : results;
|
||||
// return (hasNextPage, items);
|
||||
// }
|
||||
//
|
||||
// Future<List<String>> _mapGenreNamesToIds(List<String> genreNames, String entryType) async {
|
||||
// if (genreNames.isEmpty) return [];
|
||||
// final genresResponse = await _shikimoriGraphQLService.query<ShikimoriGenresGraphqlEntity>(
|
||||
// query: shikimori_queries.shikimoriGenresListQuery,
|
||||
// fromJson: ShikimoriGenresGraphqlEntity.fromJson,
|
||||
// variables: {"entryType": entryType},
|
||||
// );
|
||||
// throwIfGraphQlError(genresResponse);
|
||||
// final genreMap = <String, String>{};
|
||||
// for (final genre in genresResponse.data.genres) {
|
||||
// genreMap[genre.name.toLowerCase()] = genre.id;
|
||||
// }
|
||||
// return genreNames
|
||||
// .map((name) => genreMap[name.toLowerCase()])
|
||||
// .whereType<String>()
|
||||
// .toList();
|
||||
// }
|
||||
|
||||
String _mapSortToShikimori(String sort) {
|
||||
final parts = sort.toLowerCase().split('_');
|
||||
if (parts.length < 2) return 'popularity';
|
||||
final field = parts.first;
|
||||
switch (field) {
|
||||
case 'popularity':
|
||||
return 'popularity';
|
||||
case 'score':
|
||||
return 'ranked';
|
||||
case 'startdate':
|
||||
case 'start_date':
|
||||
return 'aired_on';
|
||||
case 'title':
|
||||
return 'name';
|
||||
default:
|
||||
return 'popularity';
|
||||
}
|
||||
}
|
||||
|
||||
String _mapAiringStatusToShikimori(String status) {
|
||||
switch (status.toLowerCase().replaceAll(' ', '_')) {
|
||||
case 'releasing':
|
||||
return 'ongoing';
|
||||
case 'finished':
|
||||
return 'released';
|
||||
case 'not_yet_released':
|
||||
return 'anons';
|
||||
case 'hiatus':
|
||||
return 'paused';
|
||||
case 'cancelled':
|
||||
return 'discontinued';
|
||||
default:
|
||||
return status.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
String _mapFormatToShikimoriKind(String format) {
|
||||
switch (format.toLowerCase().replaceAll(' ', '_')) {
|
||||
case 'manga':
|
||||
return 'manga';
|
||||
case 'manhwa':
|
||||
return 'manhwa';
|
||||
case 'manhua':
|
||||
return 'manhua';
|
||||
case 'novel':
|
||||
return 'light_novel';
|
||||
case 'one_shot':
|
||||
return 'one_shot';
|
||||
case 'doujinshi':
|
||||
return 'doujin';
|
||||
default:
|
||||
return format.toLowerCase().replaceAll(' ', '_');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ShikimoriMangaFormatFilters { manga, manhwa, manhua, light_novel, one_shot, doujin }
|
||||
|
||||
enum ShikimoriMangaStatusFilters { ongoing, released, anons, paused, discontinued }
|
||||
|
||||
enum ShikimoriMangaSortOptions { popularity, ranked, name, aired_on }
|
||||
|
||||
enum ShikimoriMangaSortOrder { asc, desc }
|
||||
@@ -1,2 +1,4 @@
|
||||
export 'user_repository_local.dart';
|
||||
export 'user_repository_anilist.dart';
|
||||
export 'user_repository_anilist.dart';
|
||||
export 'anime_repository_shikimori.dart';
|
||||
export 'manga_repository_shikimori.dart';
|
||||
@@ -7,8 +7,8 @@ import 'package:shelf/shelf.dart' as shelf;
|
||||
import 'package:shelf/shelf_io.dart' as shelfio;
|
||||
import 'package:unyo/core/services/api/dto/anilist/auth_token_dto.dart';
|
||||
import 'package:unyo/core/services/api/dto/anilist/media_collection_graphql_entity.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_anime_model.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_manga_model.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_anime_model.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_manga_model.dart';
|
||||
import 'package:unyo/data/repositories/repository_mixin.dart';
|
||||
import 'package:unyo/domain/entities/media/anime.dart';
|
||||
import 'package:unyo/domain/entities/media/manga.dart';
|
||||
@@ -24,7 +24,7 @@ import 'package:unyo/core/services/api/graphql/graphql_response.dart';
|
||||
import 'package:unyo/core/services/api/graphql/graphql_service.dart';
|
||||
import 'package:unyo/core/services/api/http/api_response.dart';
|
||||
import 'package:unyo/core/services/api/http/http_service.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/domain/repositories/repositories.dart';
|
||||
import 'package:unyo/domain/entities/user/user.dart';
|
||||
|
||||
|
||||
@@ -81,8 +81,8 @@ abstract class SettingsModel with _$SettingsModel implements Settings {
|
||||
@HiveField(16) @Default(false) bool enableNsfwContent,
|
||||
@HiveField(17) @ColorConverter() @Default(Color(0xFF2196F3)) Color themeColor,
|
||||
@HiveField(18) @Default(true) bool useWallpaperAsThemeColor,
|
||||
@HiveField(19) @Default([config.aniyomiExtensionsRepositoryUrl]) List<String> aniyomiExtensionsRepositories,
|
||||
@HiveField(20) @Default([config.tachiyomiExtensionsRepositoryUrl]) List<String> tachiyomiExtensionsRepositories,
|
||||
@HiveField(19) @Default([config.aniyomiExtensionsDefaultRepositoryUrl]) List<String> aniyomiExtensionsRepositories,
|
||||
@HiveField(20) @Default([config.tachiyomiExtensionsDefaultRepositoryUrl]) List<String> tachiyomiExtensionsRepositories,
|
||||
}) = _SettingsModel;
|
||||
|
||||
factory SettingsModel.empty() =>
|
||||
|
||||
@@ -227,7 +227,7 @@ return $default(_that.language,_that.service,_that.episodeService,_that.installe
|
||||
@JsonSerializable()
|
||||
|
||||
class _SettingsModel implements SettingsModel {
|
||||
const _SettingsModel({@HiveField(0) this.language = 'en', @HiveField(1) this.service = Service.anilist, @HiveField(2) this.episodeService = EpisodeService.anizip, @HiveField(3)@ExtensionConverter() final List<Extension> installedAnimeExtensions = const [], @HiveField(4)@ExtensionConverter() final List<Extension> installedMangaExtensions = const [], @HiveField(7)@ExtensionConverter() final Map<String, Extension> mediaExtensionConfigs = const {}, @HiveField(8) this.mediaTitleLanguage = 'userPreferred', @HiveField(9) this.episodeTitleLanguage = 'en', @HiveField(10) this.enableDiscordRichPresence = true, @HiveField(11) this.automaticallySkipOpening = false, @HiveField(12) this.automaticallySkipEnding = false, @HiveField(13) this.manualSkipTime = 85, @HiveField(14) this.autoPlayNextEpisode = false, @HiveField(15) this.enableOpenSubtitlesIntegration = false, @HiveField(16) this.enableNsfwContent = false, @HiveField(17)@ColorConverter() this.themeColor = const Color(0xFF2196F3), @HiveField(18) this.useWallpaperAsThemeColor = true, @HiveField(19) final List<String> aniyomiExtensionsRepositories = const [config.aniyomiExtensionsRepositoryUrl], @HiveField(20) final List<String> tachiyomiExtensionsRepositories = const [config.tachiyomiExtensionsRepositoryUrl]}): _installedAnimeExtensions = installedAnimeExtensions,_installedMangaExtensions = installedMangaExtensions,_mediaExtensionConfigs = mediaExtensionConfigs,_aniyomiExtensionsRepositories = aniyomiExtensionsRepositories,_tachiyomiExtensionsRepositories = tachiyomiExtensionsRepositories;
|
||||
const _SettingsModel({@HiveField(0) this.language = 'en', @HiveField(1) this.service = Service.anilist, @HiveField(2) this.episodeService = EpisodeService.anizip, @HiveField(3)@ExtensionConverter() final List<Extension> installedAnimeExtensions = const [], @HiveField(4)@ExtensionConverter() final List<Extension> installedMangaExtensions = const [], @HiveField(7)@ExtensionConverter() final Map<String, Extension> mediaExtensionConfigs = const {}, @HiveField(8) this.mediaTitleLanguage = 'userPreferred', @HiveField(9) this.episodeTitleLanguage = 'en', @HiveField(10) this.enableDiscordRichPresence = true, @HiveField(11) this.automaticallySkipOpening = false, @HiveField(12) this.automaticallySkipEnding = false, @HiveField(13) this.manualSkipTime = 85, @HiveField(14) this.autoPlayNextEpisode = false, @HiveField(15) this.enableOpenSubtitlesIntegration = false, @HiveField(16) this.enableNsfwContent = false, @HiveField(17)@ColorConverter() this.themeColor = const Color(0xFF2196F3), @HiveField(18) this.useWallpaperAsThemeColor = true, @HiveField(19) final List<String> aniyomiExtensionsRepositories = const [config.aniyomiExtensionsDefaultRepositoryUrl], @HiveField(20) final List<String> tachiyomiExtensionsRepositories = const [config.tachiyomiExtensionsDefaultRepositoryUrl]}): _installedAnimeExtensions = installedAnimeExtensions,_installedMangaExtensions = installedMangaExtensions,_mediaExtensionConfigs = mediaExtensionConfigs,_aniyomiExtensionsRepositories = aniyomiExtensionsRepositories,_tachiyomiExtensionsRepositories = tachiyomiExtensionsRepositories;
|
||||
factory _SettingsModel.fromJson(Map<String, dynamic> json) => _$SettingsModelFromJson(json);
|
||||
|
||||
@override@JsonKey()@HiveField(0) final String language;
|
||||
|
||||
@@ -171,12 +171,12 @@ _SettingsModel _$SettingsModelFromJson(
|
||||
(json['aniyomiExtensionsRepositories'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList() ??
|
||||
const [config.aniyomiExtensionsRepositoryUrl],
|
||||
const [config.aniyomiExtensionsDefaultRepositoryUrl],
|
||||
tachiyomiExtensionsRepositories:
|
||||
(json['tachiyomiExtensionsRepositories'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList() ??
|
||||
const [config.tachiyomiExtensionsRepositoryUrl],
|
||||
const [config.tachiyomiExtensionsDefaultRepositoryUrl],
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SettingsModelToJson(
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:unyo/core/enums/episode_service.dart';
|
||||
import 'package:unyo/core/enums/service.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_anime_details.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_manga_details.dart';
|
||||
import 'package:unyo/data/models/anilist/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/local_user_model.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_anime_details.dart';
|
||||
import 'package:unyo/data/models/anilist/media/anilist_manga_details.dart';
|
||||
import 'package:unyo/data/models/anilist/user/anilist_user_model.dart';
|
||||
import 'package:unyo/data/models/local/user/local_user_model.dart';
|
||||
import 'package:unyo/domain/entities/extension/extension.dart';
|
||||
import 'package:unyo/domain/entities/list/media_list.dart';
|
||||
import 'package:unyo/domain/entities/list/media_list_entry.dart';
|
||||
|
||||
@@ -40,7 +40,7 @@ class TextUtils {
|
||||
case Service.kitsu:
|
||||
throw UnimplementedError();
|
||||
case Service.shikimori:
|
||||
throw UnimplementedError();
|
||||
return startDate.split("/").length > 1 ? startDate.split("/")[2] : "";
|
||||
case Service.simkl:
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user