CourseWork

This commit is contained in:
Максим Яковлев 2024-12-21 14:35:19 +04:00
parent b6ad2dee53
commit abbb4d65ef
16 changed files with 56 additions and 82 deletions

View File

@ -2,6 +2,7 @@
"@@locale": "en",
"search": "Search",
"title": "Sekiro bosses",
"liked": "liked!",
"disliked": "disliked",

View File

@ -2,6 +2,7 @@
"@@locale": "ru",
"search": "Поиск",
"title": "Боссы Sekiro",
"liked": "понравился!",
"disliked": "разонравился",

View File

@ -101,6 +101,12 @@ abstract class AppLocale {
/// **'Поиск'**
String get search;
/// No description provided for @title.
///
/// In ru, this message translates to:
/// **'Боссы Sekiro'**
String get title;
/// No description provided for @liked.
///
/// In ru, this message translates to:

View File

@ -9,6 +9,9 @@ class AppLocaleEn extends AppLocale {
@override
String get search => 'Search';
@override
String get title => 'Sekiro bosses';
@override
String get liked => 'liked!';

View File

@ -9,6 +9,9 @@ class AppLocaleRu extends AppLocale {
@override
String get search => 'Поиск';
@override
String get title => 'Боссы Sekiro';
@override
String get liked => 'понравился!';

View File

@ -8,17 +8,6 @@ class BossesDto {
factory BossesDto.fromJson(Map<String, dynamic> json) => _$BossesDtoFromJson(json);
}
@JsonSerializable(createToJson: false)
class BossesDataDto {
final String? id;
final String? type;
final BossAttributesDataDto? attributes;
const BossesDataDto({this.id, this.type, this.attributes});
factory BossesDataDto.fromJson(Map<String, dynamic> json) => _$BossesDataDtoFromJson(json);
}
@JsonSerializable(createToJson: false)
class BossAttributesDataDto {
final String? id;

View File

@ -13,16 +13,6 @@ BossesDto _$BossesDtoFromJson(Map<String, dynamic> json) => BossesDto(
.toList(),
);
BossesDataDto _$BossesDataDtoFromJson(Map<String, dynamic> json) =>
BossesDataDto(
id: json['id'] as String?,
type: json['type'] as String?,
attributes: json['attributes'] == null
? null
: BossAttributesDataDto.fromJson(
json['attributes'] as Map<String, dynamic>),
);
BossAttributesDataDto _$BossAttributesDataDtoFromJson(
Map<String, dynamic> json) =>
BossAttributesDataDto(

View File

@ -1,5 +1,7 @@
import 'package:pmu_labs/data/dtos/bosses_dto.dart';
import 'package:pmu_labs/domain/models/card.dart';
import 'package:pmu_labs/domain/models/card_data.dart';
import '../../domain/models/home_data.dart';
extension BossDataDtoToModel on BossAttributesDataDto {
CardData toDomain() => CardData(
@ -10,3 +12,8 @@ extension BossDataDtoToModel on BossAttributesDataDto {
imageUrl: imageUrl,
);
}
extension BossDtoToModel on BossesDto {
HomeData toDomain() => HomeData(
data: data?.map((e) => e.toDomain()).toList(),
);
}

View File

@ -1,7 +1,7 @@
import 'package:pmu_labs/domain/models/card.dart';
import 'package:pmu_labs/domain/models/home_data.dart';
typedef OnErrorCallback = void Function(String? error);
abstract class ApiInterface {
Future<List<CardData>?> loadData();
Future<HomeData?> loadData();
}

View File

@ -1,7 +1,8 @@
import 'package:dio/dio.dart';
import 'package:pmu_labs/data/dtos/bosses_dto.dart';
import 'package:pmu_labs/data/mappers/bosses_mapper.dart';
import 'package:pmu_labs/domain/models/card.dart';
import 'package:pmu_labs/domain/models/card_data.dart';
import 'package:pmu_labs/domain/models/home_data.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:html/parser.dart' as html;
@ -51,7 +52,7 @@ class BossesRepository extends ApiInterface {
static const String _baseUrl = 'https://sekiro.fandom.com/ru/api.php';
@override
Future<List<CardData>?> loadData({
Future<HomeData?> loadData({
OnErrorCallback? onError,
String? q,
}) async {
@ -64,7 +65,7 @@ class BossesRepository extends ApiInterface {
url =
'$_baseUrl?action=query&generator=categorymembers&gcmtitle=Category:Боссы&gcmnamespace=0&gcmlimit=50&prop=pageimages&piprop=original&format=json&origin=*';
}
final List<CardData>? data;
final HomeData? data;
BossesDto dto;
final Response<dynamic> response = await _dio.get<Map<dynamic, dynamic>>(url);
@ -74,15 +75,21 @@ class BossesRepository extends ApiInterface {
List<(String, String)> descs = [];
final Response<dynamic> respDesc = await _dio.get<Map<dynamic, dynamic>>(
'https://sekiro.fandom.com/ru/api.php?action=query&generator=categorymembers&gcmtitle=Category:Боссы&gcmnamespace=0&gcmlimit=50&prop=revisions&rvprop=content&format=json&origin=*');
for (var boss in pages.values) {
final Response<dynamic> respDesc = await _dio.get<Map<dynamic, dynamic>>(
'https://sekiro.fandom.com/ru/api.php?action=parse&page=${boss['title']}&prop=text&section=1&format=json');
final htmlContent = respDesc.data['parse']['text']['*'];
var doc = html.parse(htmlContent);
final String text = doc.body?.text as String;
descs.add((boss['title'], text));
final htmlContent = respDesc.data['query']['pages']['${boss['pageid']}']['revisions'][0]['*'];
var document = html.parse(htmlContent);
String text = document.body?.text ?? '';
text = text.split("==Галерея==")[0];
text = text.split("== Галерея ==")[0];
text = text.replaceAll(RegExp(r'\{[^\}]*\}'), '');
descs.add((boss['title'], text.trim()));
}
final transData = transformJsonToBossesDtoFormat(pages, descs);
dto = BossesDto.fromJson(transData);
if (q != null && q != "") {
@ -92,10 +99,7 @@ class BossesRepository extends ApiInterface {
}
data = dto.data?.map((e) => e.toDomain()).toList();
//for(int i = 0; i<data!.length;i++){
//data[i].id = i.toString();
//}
data = dto.toDomain();
return data;
} on DioException catch (e) {
onError?.call(e.error?.toString());

View File

@ -1,37 +0,0 @@
import 'package:pmu_labs/data/repositories/api_interface.dart';
import '../../domain/models/card.dart';
class MockRepository extends ApiInterface {
@override
Future<List<CardData>?> loadData() async {
return [
CardData('Warhammer 40000:Space Marine 2',
descriptionText: 'Читать новость',
id: '1',
imageUrl:
'https://news.xbox.com/en-us/wp-content/uploads/sites/2/2021/12/SpaceMarine2_TemporaryArtwork_4K_logo.jpg',
gameDesc: 'Обретите сверхчеловеческую мощь космодесантника. Пустите в ход смертоносные навыки и разрушительное оружие, чтобы ' +
' истребить безжалостных тиранидов. Защитите Империум в ярких одиночных боях или многопользовательских режимах с ' +
'видом от третьего лица. В продолжении экшена 2011 года Space Marine вам предстоит сразиться с врагами человечества и' +
' вновь доказать ему свою преданность в роли лейтенанта Деметрия Тита, который вернулся в ряды Ультрамаринов. Дайте отпор ' +
'ужасам Галактики в эпических боях сразу на нескольких планетах. Раскройте мрачные секреты и отбросьте тень вечной ночи.'),
CardData('Risk of rain 2',
descriptionText: 'Читать новость',
id: '2',
imageUrl: 'https://digiseller.mycdn.ink/preview/990130/p1_3675944_49000546.jpg',
gameDesc: 'Вас ожидает более тысячи созданных вручную областей. Каждая из них кишит смертельно опасными монстрами и огромными боссами,' +
' стремящимися оборвать вашу жизнь. Дойдите до финального босса и выберитесь с планеты, либо продолжите своё приключение,' +
' чтобы выяснить, как долго вы сможете продержаться. Благодаря умной системе повышения уровня ваша сила и сила ваших врагов будет постоянно расти во время игры.'),
CardData('Yakuza 0',
descriptionText: 'Читать новость',
id: '3',
imageUrl:
'https://avatars.mds.yandex.net/get-marketpic/1588570/pic3d2a9b85ee47202578aac1bb1f97fcc0/orig',
gameDesc: 'В декабре 1988 года двое героев из мира якудза — Кадзума Кирю (молодой якудза низшего ранга из региона Канто)' +
' и Горо Мадзима (менеджер кабаре, бывший якудза из региона Кансай, изгнанный из клана, но желающий во что бы' +
' то ни стало вернуться) — оказываются втянуты в борьбу за небольшой «пустой участок» земли в центре района Камуротё,' +
' который притягивает преступные силы со всей Японии.Сюжетная линия игры разбита на 2 линии, которые косвенно пересекаются по ходу истории'),
];
}
}

View File

@ -0,0 +1,6 @@
import 'package:pmu_labs/domain/models/card_data.dart';
class HomeData {
final List<CardData>? data;
HomeData({this.data});
}

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:pmu_labs/domain/models/card.dart';
import 'package:pmu_labs/domain/models/card_data.dart';
class DetailsPage extends StatelessWidget {
final CardData data;

View File

@ -1,8 +1,9 @@
import 'package:equatable/equatable.dart';
import 'package:pmu_labs/domain/models/card.dart';
import 'package:pmu_labs/domain/models/card_data.dart';
import 'package:pmu_labs/domain/models/home_data.dart';
class HomeState extends Equatable {
final List<CardData>? data;
final HomeData? data;
final bool isLoading;
final String? error;
@ -13,7 +14,7 @@ class HomeState extends Equatable {
});
HomeState copyWith({
List<CardData>? data,
HomeData? data,
bool? isLoading,
String? error,
}) =>

View File

@ -14,7 +14,7 @@ import 'package:pmu_labs/presentation/locale_bloc/locale_events.dart';
import 'package:pmu_labs/presentation/locale_bloc/locale_state.dart';
import '../../components/utils/debounce.dart';
import '../../domain/models/card.dart';
import '../../domain/models/card_data.dart';
import '../like_bloc/like_event.dart';
part 'card.dart';
@ -36,7 +36,7 @@ class _MyHomePageState extends State<MyHomePage> {
return Scaffold(
appBar: AppBar(
backgroundColor: _color,
title: Text(widget.title),
title: Text(context.locale.title),
),
body: const Body(),
);
@ -140,9 +140,9 @@ class _BodyState extends State<Body> {
onRefresh: _onRefresh,
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: state.data?.length ?? 0,
itemCount: state.data?.data?.length ?? 0,
itemBuilder: (context, index) {
final data = state.data?[index];
final data = state.data?.data?[index];
return data != null
? _Card.fromData(
data,