diff --git a/lib/data/dtos/spells_dto.dart b/lib/data/dtos/spells_dto.dart index 97728a0..13ff1ff 100644 --- a/lib/data/dtos/spells_dto.dart +++ b/lib/data/dtos/spells_dto.dart @@ -3,14 +3,14 @@ import 'package:json_annotation/json_annotation.dart'; part 'spells_dto.g.dart'; @JsonSerializable(createToJson: false) -class SpellDto { +class SpellsDto { final List? data; - const SpellDto({ + const SpellsDto({ this.data, }); - factory SpellDto.fromJson(Map json) => + factory SpellsDto.fromJson(Map json) => _$SpellDtoFromJson(json); } diff --git a/lib/data/dtos/spells_dto.g.dart b/lib/data/dtos/spells_dto.g.dart index c2f4cea..b29aaae 100644 --- a/lib/data/dtos/spells_dto.g.dart +++ b/lib/data/dtos/spells_dto.g.dart @@ -6,7 +6,7 @@ part of 'spells_dto.dart'; // JsonSerializableGenerator // ************************************************************************** -SpellDto _$SpellDtoFromJson(Map json) => SpellDto( +SpellsDto _$SpellDtoFromJson(Map json) => SpellsDto( data: (json['data'] as List?) ?.map((e) => SpellDataDto.fromJson(e as Map)) .toList(), diff --git a/lib/data/mappers/spells_mapper.dart b/lib/data/mappers/spells_mapper.dart index b041323..0945704 100644 --- a/lib/data/mappers/spells_mapper.dart +++ b/lib/data/mappers/spells_mapper.dart @@ -8,5 +8,30 @@ extension SpellsDataDtoToModel on SpellDataDto { CardData toDomain() => CardData( attributes?.name ?? 'UNKNOWN', imageUrl: attributes?.image ?? _imagePlaceHolder, + description: _makeDescription(attributes), ); } + +String _makeDescription(SpellAttributesDataDto? attributes){ + return 'incantation: ${attributes?.incantation ?? 'UNKNOWN'},\n' + 'category: ${attributes?.category ?? 'UNKNOWN'},\n' + 'creator: ${attributes?.creator ?? 'UNKNOWN'},\n' + 'effect: ${attributes?.effect ?? 'UNKNOWN'},\n' + 'hand: ${attributes?.hand ?? 'UNKNOWN'},\n' + 'light: ${attributes?.light ?? 'UNKNOWN'},\n' + 'slug: ${attributes?.slug ?? 'UNKNOWN'}' + ; +} + +/* + final String? slug; // хз + final String? category; // категория + final String? creator; // создатель + final String? effect; // воздействие + final String? hand; // взмах + final String? image; // картинка + final String? incantation; // произношение + final String? light; // цвет + final String? name; // название + final String? wiki; // ссылка на вики + */ \ No newline at end of file diff --git a/lib/data/repositories/potter_repository.dart b/lib/data/repositories/potter_repository.dart index 1e2de1f..37749ad 100644 --- a/lib/data/repositories/potter_repository.dart +++ b/lib/data/repositories/potter_repository.dart @@ -21,13 +21,40 @@ class PotterRepository extends ApiInterface { try { const String url = '$_baseUrl/v1/spells'; - final Response response = await _dio.get>( - url, - queryParameters: q != null ? {'filter[name_cont]': q} : null, - ); + SpellsDto dto; + if (q == null) { + final Response response = + await _dio.get>(url); + dto = SpellsDto.fromJson(response.data as Map); + } else { + final Response response1 = + await _dio.get>( + url, + queryParameters: q != null ? {'filter[name_cont]': q} : null, + ); + final Response response2 = + await _dio.get>( + url, + queryParameters: q != null ? {'filter[incantation_cont]': q} : null, + ); + SpellsDto dto1 = + SpellsDto.fromJson(response1.data as Map); + SpellsDto dto2 = + SpellsDto.fromJson(response2.data as Map); - final SpellDto dto = SpellDto.fromJson( - response.data as Map); + List combinedData = [ + ...?dto1.data, // добавляем данные из dto1 + ...?dto2.data // добавляем данные из dto2 + ]; +// Удаляем дубликаты по полю id + Map uniqueSpellsMap = { + for (var spell in combinedData) spell.id: spell + }; +// Преобразуем обратно в список + List uniqueSpells = uniqueSpellsMap.values.toList(); +// Создаем новый SpellsDto с уникальными данными + dto = SpellsDto(data: uniqueSpells); + } final List? data = dto.data?.map((e) => e.toDomain()).toList(); return data; } on DioException catch (e) { @@ -35,4 +62,4 @@ class PotterRepository extends ApiInterface { return null; } } -} \ No newline at end of file +} diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart index 6361c41..8c61a87 100644 --- a/lib/domain/models/card.dart +++ b/lib/domain/models/card.dart @@ -1,9 +1,11 @@ class CardData { final String text; + final String? description; final String? imageUrl; CardData( this.text, { + this.description, this.imageUrl, }); } diff --git a/lib/presentation/details_page/details_page.dart b/lib/presentation/details_page/details_page.dart index b55343d..cd1bd23 100644 --- a/lib/presentation/details_page/details_page.dart +++ b/lib/presentation/details_page/details_page.dart @@ -53,6 +53,30 @@ class DetailsPage extends StatelessWidget { ), ), ), + Container( + margin: const EdgeInsets.all(20), + width: double.infinity, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: const Color.fromARGB(255, 250, 235, 159), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(.5), + blurRadius: 8, + offset: const Offset(0, 5), + spreadRadius: 4, + ) + ]), + child: Center( + child: Padding( + padding: const EdgeInsets.all(10), + child: Text( + data.description ?? '', + style: Theme.of(context).textTheme.headlineLarge, + ), + ), + ), + ), ], ), ), diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart index 3a0e50b..85111f1 100644 --- a/lib/presentation/home_page/card.dart +++ b/lib/presentation/home_page/card.dart @@ -4,11 +4,12 @@ typedef OnLikeCallback = void Function(bool isLiked)?; class _Card extends StatefulWidget { final String _text; + final String? description; final String? imageUrl; final OnLikeCallback onLike; final VoidCallback? onTap; - const _Card(this._text, {Key? key, this.imageUrl, this.onLike, this.onTap}) + const _Card(this._text, {Key? key, this.imageUrl, this.description, this.onLike, this.onTap}) : super(key: key); factory _Card.fromData( @@ -19,6 +20,7 @@ class _Card extends StatefulWidget { _Card( data.text, imageUrl: data.imageUrl, + description: data.description, onLike: onLike, onTap: onTap, ); @@ -69,11 +71,24 @@ class _CardState extends State<_Card> { Expanded( child: Padding( padding: const EdgeInsets.only(left: 8.0, bottom: 8), - child: Text( - widget._text, - style: Theme.of(context).textTheme.headlineMedium, - overflow: TextOverflow.ellipsis, - maxLines: 4, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget._text, + style: Theme.of(context).textTheme.headlineMedium, + overflow: TextOverflow.ellipsis, + maxLines: 4, + ), + Flexible( + child: Text( + widget.description ?? '', + style: Theme.of(context).textTheme.bodyLarge, + overflow: TextOverflow.ellipsis, + maxLines: 7, + ), + ), + ], ), ), ), diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart index 630e3d5..aafdbd4 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -39,46 +39,70 @@ class _BodyState extends State { final repo = PotterRepository(); @override - Widget build(BuildContext context) { - data = repo.loadData( - onError: (e) => showErrorDialog(context, error: e), - ); + void initState() { + data = repo.loadData(onError: (e) => showErrorDialog(context, error: e)); + super.initState(); + } + @override + Widget build(BuildContext context) { return Center( - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CupertinoSearchTextField( - controller: searchController, - onChanged: (search) { - setState(() {}); - data = repo.loadData( - q: search, - onError: (e) => showErrorDialog(context, error: e), + child: Stack( + children: [ + Positioned.fill( + child: FutureBuilder?>( + future: data, + builder: (context, snapshot) { + var cards = Column( + children: [], ); + cards.children.add(Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8), + child: CupertinoSearchTextField(), + )); + cards.children.addAll( + snapshot.data + ?.map((e) => _Card.fromData( + e, + onLike: (bool isLiked) { + _showSnackBar(context, isLiked); + }, + onTap: () => _navToDetails(context, e), + )) + .toList() ?? + [], + ); + return snapshot.hasData + ? SingleChildScrollView( + child: cards, + ) + : Center(child: CircularProgressIndicator()); }, ), - FutureBuilder?>( - future: data, - builder: (context, snapshot) => snapshot.hasData - ? Column( - mainAxisAlignment: MainAxisAlignment.center, - children: snapshot.data - ?.map((e) => _Card.fromData( - e, - onLike: (bool isLiked) { - _showSnackBar(context, isLiked); - }, - onTap: () => _navToDetails(context, e), - )) - .toList() ?? - [], - ) - : const CircularProgressIndicator(), + ), + Align( + alignment: Alignment.topCenter, + child: Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8), + child: CupertinoSearchTextField( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(20), + bottomRight: Radius.circular(20), + ), + backgroundColor: Colors.amberAccent, + controller: searchController, + onChanged: (search) { + setState(() { + data = repo.loadData( + q: search, + onError: (e) => showErrorDialog(context, error: e), + ); + }); + }, + ), ), - ], - ), + ), + ], ), ); }