Skip to content

Commit

Permalink
Merge pull request #41 from andannn/profile
Browse files Browse the repository at this point in the history
Profile favorite page
  • Loading branch information
andannn authored Oct 23, 2023
2 parents e9e83c1 + 6820aad commit 744c3a1
Show file tree
Hide file tree
Showing 36 changed files with 1,579 additions and 55 deletions.
77 changes: 77 additions & 0 deletions lib/app/local/ani_flow_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ abstract class AFLocalizations {

String get topManhwa;

String get favorite;

String get animeList;

String get mangaList;

String get reviews;

String get social;

String get animeLabel;

String get mangaLabel;

static AFLocalizations of([BuildContext? context]) {
return Localizations.of<AFLocalizations>(
context ?? globalContext!, AFLocalizations)!;
Expand Down Expand Up @@ -213,6 +227,27 @@ class EnAniFlowLocalizations extends AFLocalizations {

@override
String get topManhwa => 'Top Manhwa';

@override
String get favorite => 'Favorite';

@override
String get animeList => 'Anime List';

@override
String get mangaList => 'Manga List';

@override
String get reviews => 'Reviews';

@override
String get animeLabel => 'Anime';

@override
String get mangaLabel => 'Manga';

@override
String get social => 'Social';
}

class JaAniFLowLocalizations extends AFLocalizations {
Expand Down Expand Up @@ -338,6 +373,27 @@ class JaAniFLowLocalizations extends AFLocalizations {

@override
String get topManhwa => 'Top Manhwa';

@override
String get favorite => 'Favorites';

@override
String get animeList => 'Anime List';

@override
String get mangaList => 'Manga List';

@override
String get reviews => 'Reviews';

@override
String get animeLabel => 'アニメ';

@override
String get mangaLabel => '漫画';

@override
String get social => 'Social';
}

class CNAniFlowLocalizations extends AFLocalizations {
Expand Down Expand Up @@ -463,4 +519,25 @@ class CNAniFlowLocalizations extends AFLocalizations {

@override
String get topManhwa => 'Top Manhwa';

@override
String get favorite => 'Favorite';

@override
String get animeList => 'Anime List';

@override
String get mangaList => 'Manga List';

@override
String get reviews => 'Reviews';

@override
String get animeLabel => '动画';

@override
String get mangaLabel => '漫画';

@override
String get social => 'Social';
}
2 changes: 1 addition & 1 deletion lib/app/navigation/ani_flow_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class AFRouterDelegate extends RouterDelegate<AniFlowRoutePath>
notifyListeners();
}

void navigateToDetailAnime(String animeId) {
void navigateToDetailMedia(String animeId) {
_backStack += [DetailAnimeRoutePath(animeId)];

notifyListeners();
Expand Down
23 changes: 23 additions & 0 deletions lib/core/common/model/favorite_category.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:aniflow/app/local/ani_flow_localizations.dart';
import 'package:flutter/material.dart';

enum FavoriteType {
anime('favorite_anime'),
manga('favorite_manga'),
character('favorite_staff'),
staff('favorite_character');

const FavoriteType(this.contentValues);

final String contentValues;
}

extension FavoriteTypeEx on FavoriteType {
String getLocalString(BuildContext context) => switch (this) {
FavoriteType.anime => AFLocalizations.of(context).animeLabel,
FavoriteType.manga => AFLocalizations.of(context).mangaLabel,
FavoriteType.character => AFLocalizations.of(context).characters,
FavoriteType.staff => AFLocalizations.of(context).staff,
};
}

112 changes: 112 additions & 0 deletions lib/core/data/favorite_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import 'dart:async';

import 'package:aniflow/core/common/model/favorite_category.dart';
import 'package:aniflow/core/common/model/media_type.dart';
import 'package:aniflow/core/common/util/load_page_util.dart';
import 'package:aniflow/core/data/load_result.dart';
import 'package:aniflow/core/data/model/character_model.dart';
import 'package:aniflow/core/data/model/media_model.dart';
import 'package:aniflow/core/database/aniflow_database.dart';
import 'package:aniflow/core/database/dao/media_dao.dart';
import 'package:aniflow/core/database/dao/media_list_dao.dart';
import 'package:aniflow/core/database/dao/user_data_dao.dart';
import 'package:aniflow/core/database/model/character_entity.dart';
import 'package:aniflow/core/database/model/media_entity.dart';
import 'package:aniflow/core/network/ani_list_data_source.dart';
import 'package:aniflow/core/network/model/character_dto.dart';
import 'package:aniflow/core/network/util/http_status_util.dart';

abstract class FavoriteRepository {
Future<LoadResult<List<MediaModel>>> loadFavoriteMediaByPage(
{required MediaType type, required LoadType loadType, String? userId});

Future<LoadResult<List<CharacterModel>>> loadFavoriteCharacterByPage(
{required LoadType loadType, String? userId});
}

class FavoriteRepositoryImpl implements FavoriteRepository {
final AniListDataSource aniListDataSource = AniListDataSource();
final UserDataDao userDataDao = AniflowDatabase().getUserDataDao();
final MediaInformationDao mediaInfoDao =
AniflowDatabase().getMediaInformationDaoDao();
final MediaListDao mediaListDao = AniflowDatabase().getMediaListDao();

@override
Future<LoadResult<List<MediaModel>>> loadFavoriteMediaByPage(
{required MediaType type,
required LoadType loadType,
String? userId}) async {
userId ??= (await _getCurrentAuthUserId());
if (userId == null) {
return LoadError(const UnauthorizedException());
}

return LoadPageUtil.loadPage(
type: loadType,
onGetNetworkRes: (int page, int perPage) {
if (type == MediaType.anime) {
return aniListDataSource.getFavoriteAnimeMedia(
userId: userId!,
page: page,
perPage: perPage,
);
} else {
return aniListDataSource.getFavoriteMangaMedia(
userId: userId!,
page: page,
perPage: perPage,
);
}
},
onInsertEntityToDB: (List<MediaEntity> entities) async {
await mediaInfoDao.upsertMediaInformation(entities);
if (type == MediaType.anime) {
await mediaListDao.insertFavoritesCrossRef(
userId!, FavoriteType.anime, entities.map((e) => e.id).toList());
} else {
await mediaListDao.insertFavoritesCrossRef(
userId!, FavoriteType.manga, entities.map((e) => e.id).toList());
}
},
onClearDbCache: () async {},
onGetEntityFromDB: (int page, int perPage) =>
mediaListDao.getFavoriteMedia(type, userId!, page, perPage),
mapDtoToEntity: (dto) => MediaEntity.fromNetworkModel(dto),
mapEntityToModel: (entity) => MediaModel.fromDatabaseModel(entity),
);
}

@override
Future<LoadResult<List<CharacterModel>>> loadFavoriteCharacterByPage(
{required LoadType loadType, String? userId}) async {
userId ??= (await _getCurrentAuthUserId());
if (userId == null) {
return LoadError(const UnauthorizedException());
}

return LoadPageUtil.loadPage<CharacterDto, CharacterEntity, CharacterModel>(
type: loadType,
onGetNetworkRes: (int page, int perPage) {
return aniListDataSource.getFavoriteCharacter(
userId: userId!,
page: page,
perPage: perPage,
);
},
onInsertEntityToDB: (List<CharacterEntity> entities) async {
await mediaInfoDao.insertCharacters(entities: entities);
await mediaListDao.insertFavoritesCrossRef(userId!,
FavoriteType.character, entities.map((e) => e.id).toList());
},
onClearDbCache: () async {},
onGetEntityFromDB: (int page, int perPage) =>
mediaListDao.getFavoriteCharacters(userId!, page, perPage),
mapDtoToEntity: (dto) => CharacterEntity.fromDto(dto),
mapEntityToModel: (entity) => CharacterModel.fromDatabaseEntity(entity),
);
}

Future<String?> _getCurrentAuthUserId() async {
return (await userDataDao.getUserData())?.id;
}
}
2 changes: 1 addition & 1 deletion lib/core/data/media_list_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class MediaListRepositoryImpl extends MediaListRepository {

try {
/// post mutation to network and insert result to database.
final result = await authDataSource.saveAnimeToAnimeList(
final result = await authDataSource.saveMediaToMediaList(
MediaListMutationParam(
entryId: int.tryParse(entryId ?? ''),
mediaId: int.parse(animeId),
Expand Down
2 changes: 1 addition & 1 deletion lib/core/data/search_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class SearchRepositoryImpl implements SearchRepository {
required int perPage,
required String search,
required MediaType type}) {
return LoadPageUtil.loadPageWithoutDBCache<MediaDto, MediaModel>(
return LoadPageUtil.loadPageWithoutDBCache(
page: page,
perPage: perPage,
onGetNetworkRes: (int page, int perPage) => dataSource.searchAnimePage(
Expand Down
22 changes: 16 additions & 6 deletions lib/core/database/aniflow_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mixin Tables {
static const String mediaListTable = 'media_list_table';
static const String airingSchedulesTable = 'airing_schedules_table';
static const String mediaExternalLickTable = 'media_external_link_table';
static const String favoriteInfoCrossRefTable = 'favoriteInfoTable';
}

class AniflowDatabase {
Expand Down Expand Up @@ -134,12 +135,12 @@ class AniflowDatabase {

await _aniflowDB!.execute(
'create table if not exists ${Tables.mediaCharacterCrossRefTable} ('
'${MediaCharacterCrossRefColumns.mediaId} text,'
'${MediaCharacterCrossRefColumns.characterId} text,'
'${MediaCharacterCrossRefColumns.timeStamp} integer,'
'primary key (${MediaCharacterCrossRefColumns.mediaId}, ${MediaCharacterCrossRefColumns.characterId}),'
'foreign key (${MediaCharacterCrossRefColumns.mediaId}) references ${Tables.mediaTable} (${MediaTableColumns.id}),'
'foreign key (${MediaCharacterCrossRefColumns.characterId}) references ${Tables.characterTable} (${CharacterColumns.id})'
'${CharacterCrossRefColumns.mediaId} text,'
'${CharacterCrossRefColumns.characterId} text,'
'${CharacterCrossRefColumns.timeStamp} integer,'
'primary key (${CharacterCrossRefColumns.mediaId}, ${CharacterCrossRefColumns.characterId}),'
'foreign key (${CharacterCrossRefColumns.mediaId}) references ${Tables.mediaTable} (${MediaTableColumns.id}),'
'foreign key (${CharacterCrossRefColumns.characterId}) references ${Tables.characterTable} (${CharacterColumns.id})'
')');

await _aniflowDB!.execute(
Expand Down Expand Up @@ -188,5 +189,14 @@ class AniflowDatabase {
'${MediaExternalLinkColumnValues.icon} text,'
'foreign key (${MediaExternalLinkColumnValues.mediaId}) references ${Tables.mediaTable} (${MediaTableColumns.id})'
')');

await _aniflowDB!.execute(
'CREATE TABLE IF NOT EXISTS ${Tables.favoriteInfoCrossRefTable} ('
'${FavoriteInfoCrossRefTableColumn.favoriteType} text,'
'${FavoriteInfoCrossRefTableColumn.id} text,'
'${FavoriteInfoCrossRefTableColumn.userId} text, '
'primary key (${FavoriteInfoCrossRefTableColumn.favoriteType},${FavoriteInfoCrossRefTableColumn.id},${FavoriteInfoCrossRefTableColumn.userId})'
')');

}
}
Loading

0 comments on commit 744c3a1

Please sign in to comment.