lab 7 in process

This commit is contained in:
revengel66 2024-12-17 14:33:28 +04:00
parent 903878a412
commit 7afab39d5a
32 changed files with 577 additions and 336 deletions

6
l10n.yaml Normal file
View File

@ -0,0 +1,6 @@
arb-dir: l10n
template-arb-file: app_ru.arb
output-localization-file: app_locale.dart
output-dir: lib/components/locale/l10n
output-class: AppLocale
synthetic-package: false

27
Makefile Normal file
View File

@ -0,0 +1,27 @@
gen:
flutter pub run build_runner build --delete-conflicting-outputs
icon:
flutter pub run flutter_launcher_icons:main
hello:
echo "Hi!"; \
echo "I`m makefile"; \
echo "^_^"
init_res:
dart pub global activate flutter_asset_generator
format:
dart format . --line-length 100
activate_fgen:
flutter pub global activate fgen
res:
fgen --output lib/components/resources.g.dart --no-watch --no-preview; \
make format
loc:
flutter gen-l10n && \
make format

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 20 KiB

18
assets/svg/ru.svg Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 -4 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_503_2726)">
<rect x="0.25" y="0.25" width="27.5" height="19.5" rx="1.75" fill="white" stroke="#F5F5F5" stroke-width="0.5"/>
<mask id="mask0_503_2726" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="28" height="20">
<rect x="0.25" y="0.25" width="27.5" height="19.5" rx="1.75" fill="white" stroke="white" stroke-width="0.5"/>
</mask>
<g mask="url(#mask0_503_2726)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 13.3333H28V6.66667H0V13.3333Z" fill="#0C47B7"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 20H28V13.3333H0V20Z" fill="#E53B35"/>
</g>
</g>
<defs>
<clipPath id="clip0_503_2726">
<rect width="28" height="20" rx="2" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 949 B

2
assets/svg/uk.svg Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--twemoji" preserveAspectRatio="xMidYMid meet"><path fill="#00247D" d="M0 9.059V13h5.628zM4.664 31H13v-5.837zM23 25.164V31h8.335zM0 23v3.941L5.63 23zM31.337 5H23v5.837zM36 26.942V23h-5.631zM36 13V9.059L30.371 13zM13 5H4.664L13 10.837z"></path><path fill="#CF1B2B" d="M25.14 23l9.712 6.801a3.977 3.977 0 0 0 .99-1.749L28.627 23H25.14zM13 23h-2.141l-9.711 6.8c.521.53 1.189.909 1.938 1.085L13 23.943V23zm10-10h2.141l9.711-6.8a3.988 3.988 0 0 0-1.937-1.085L23 12.057V13zm-12.141 0L1.148 6.2a3.994 3.994 0 0 0-.991 1.749L7.372 13h3.487z"></path><path fill="#EEE" d="M36 21H21v10h2v-5.836L31.335 31H32a3.99 3.99 0 0 0 2.852-1.199L25.14 23h3.487l7.215 5.052c.093-.337.158-.686.158-1.052v-.058L30.369 23H36v-2zM0 21v2h5.63L0 26.941V27c0 1.091.439 2.078 1.148 2.8l9.711-6.8H13v.943l-9.914 6.941c.294.07.598.116.914.116h.664L13 25.163V31h2V21H0zM36 9a3.983 3.983 0 0 0-1.148-2.8L25.141 13H23v-.943l9.915-6.942A4.001 4.001 0 0 0 32 5h-.663L23 10.837V5h-2v10h15v-2h-5.629L36 9.059V9zM13 5v5.837L4.664 5H4a3.985 3.985 0 0 0-2.852 1.2l9.711 6.8H7.372L.157 7.949A3.968 3.968 0 0 0 0 9v.059L5.628 13H0v2h15V5h-2z"></path><path fill="#CF1B2B" d="M21 15V5h-6v10H0v6h15v10h6V21h15v-6z"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/wp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

7
l10n/app_en.arb Normal file
View File

@ -0,0 +1,7 @@
{
"@@locale": "en",
"search": "Search",
"liked": "liked!",
"disliked": "disliked :(",
"arbEnding": "Чтобы не забыть про отсутствие запятой :)"
}

7
l10n/app_ru.arb Normal file
View File

@ -0,0 +1,7 @@
{
"@@locale": "ru",
"search": "Поиск",
"liked": "понравился!",
"disliked": "разонравился :(",
"arbEnding": "Чтобы не забыть про отсутствие запятой :)"
}

View File

@ -0,0 +1,12 @@
/// Generate by [asset_generator](https://github.com/fluttercandies/flutter_asset_generator) library.
/// PLEASE DO NOT EDIT MANUALLY.
// ignore_for_file: constant_identifier_names
class R {
const R._();
/// ![preview](file://C:\Users\Natalia\Desktop\5semestr\PMD\pmd_lab\assets\svg\ru.svg)
static const String ASSETS_SVG_RU_SVG = 'assets/svg/ru.svg';
/// ![preview](file://C:\Users\Natalia\Desktop\5semestr\PMD\pmd_lab\assets\svg\uk.svg)
static const String ASSETS_SVG_UK_SVG = 'assets/svg/uk.svg';
}

View File

@ -9,9 +9,9 @@ class Debounce {
static Timer? _timer; static Timer? _timer;
static void run( static void run(
VoidCallback action, { VoidCallback action, {
Duration delay = const Duration(milliseconds: 500), Duration delay = const Duration(milliseconds: 500),
}) { }) {
_timer?.cancel(); _timer?.cancel();
_timer = Timer(delay, action); _timer = Timer(delay, action);
} }

View File

@ -2,9 +2,8 @@ import 'package:json_annotation/json_annotation.dart';
part 'characters_dto.g.dart'; part 'characters_dto.g.dart';
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class CharactersDto{ class CharactersDto {
final List<CharactersDataDto>? data; final List<CharactersDataDto>? data;
final MetaDto? meta; final MetaDto? meta;
const CharactersDto({this.data, this.meta}); const CharactersDto({this.data, this.meta});
@ -12,23 +11,25 @@ class CharactersDto{
} }
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class CharactersDataDto{ class CharactersDataDto {
final String? id; final String? id;
final String? type; final String? type;
final CharasterAttributesDataDto? attributes; final CharasterAttributesDataDto? attributes;
const CharactersDataDto({this.id, this.type, this.attributes}); const CharactersDataDto({this.id, this.type, this.attributes});
factory CharactersDataDto.fromJson(Map<String, dynamic> json) => _$CharactersDataDtoFromJson(json); factory CharactersDataDto.fromJson(Map<String, dynamic> json) =>
_$CharactersDataDtoFromJson(json);
} }
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class CharasterAttributesDataDto{ class CharasterAttributesDataDto {
final String? name; final String? name;
final String? born; final String? born;
final String? died; final String? died;
final String? image; final String? image;
const CharasterAttributesDataDto({this.name, this.born, this.died, this.image}); const CharasterAttributesDataDto({this.name, this.born, this.died, this.image});
factory CharasterAttributesDataDto.fromJson(Map<String, dynamic> json) => _$CharasterAttributesDataDtoFromJson(json); factory CharasterAttributesDataDto.fromJson(Map<String, dynamic> json) =>
_$CharasterAttributesDataDtoFromJson(json);
} }
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
@ -49,4 +50,4 @@ class PaginationDto {
const PaginationDto({this.current, this.next, this.last}); const PaginationDto({this.current, this.next, this.last});
factory PaginationDto.fromJson(Map<String, dynamic> json) => _$PaginationDtoFromJson(json); factory PaginationDto.fromJson(Map<String, dynamic> json) => _$PaginationDtoFromJson(json);
} }

View File

@ -6,28 +6,22 @@ part of 'characters_dto.dart';
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
CharactersDto _$CharactersDtoFromJson(Map<String, dynamic> json) => CharactersDto _$CharactersDtoFromJson(Map<String, dynamic> json) => CharactersDto(
CharactersDto(
data: (json['data'] as List<dynamic>?) data: (json['data'] as List<dynamic>?)
?.map((e) => CharactersDataDto.fromJson(e as Map<String, dynamic>)) ?.map((e) => CharactersDataDto.fromJson(e as Map<String, dynamic>))
.toList(), .toList(),
meta: json['meta'] == null meta: json['meta'] == null ? null : MetaDto.fromJson(json['meta'] as Map<String, dynamic>),
? null
: MetaDto.fromJson(json['meta'] as Map<String, dynamic>),
); );
CharactersDataDto _$CharactersDataDtoFromJson(Map<String, dynamic> json) => CharactersDataDto _$CharactersDataDtoFromJson(Map<String, dynamic> json) => CharactersDataDto(
CharactersDataDto(
id: json['id'] as String?, id: json['id'] as String?,
type: json['type'] as String?, type: json['type'] as String?,
attributes: json['attributes'] == null attributes: json['attributes'] == null
? null ? null
: CharasterAttributesDataDto.fromJson( : CharasterAttributesDataDto.fromJson(json['attributes'] as Map<String, dynamic>),
json['attributes'] as Map<String, dynamic>),
); );
CharasterAttributesDataDto _$CharasterAttributesDataDtoFromJson( CharasterAttributesDataDto _$CharasterAttributesDataDtoFromJson(Map<String, dynamic> json) =>
Map<String, dynamic> json) =>
CharasterAttributesDataDto( CharasterAttributesDataDto(
name: json['name'] as String?, name: json['name'] as String?,
born: json['born'] as String?, born: json['born'] as String?,
@ -41,8 +35,7 @@ MetaDto _$MetaDtoFromJson(Map<String, dynamic> json) => MetaDto(
: PaginationDto.fromJson(json['pagination'] as Map<String, dynamic>), : PaginationDto.fromJson(json['pagination'] as Map<String, dynamic>),
); );
PaginationDto _$PaginationDtoFromJson(Map<String, dynamic> json) => PaginationDto _$PaginationDtoFromJson(Map<String, dynamic> json) => PaginationDto(
PaginationDto(
current: (json['current'] as num?)?.toInt(), current: (json['current'] as num?)?.toInt(),
next: (json['next'] as num?)?.toInt(), next: (json['next'] as num?)?.toInt(),
last: (json['last'] as num?)?.toInt(), last: (json['last'] as num?)?.toInt(),

View File

@ -2,30 +2,28 @@ import 'package:pmd_lab/data/dtos/characters_dto.dart';
import 'package:pmd_lab/domain/models/card.dart'; import 'package:pmd_lab/domain/models/card.dart';
import 'package:pmd_lab/domain/models/home.dart'; import 'package:pmd_lab/domain/models/home.dart';
const _imagePlaceholder = 'https://cdn-icons-png.flaticon.com/512/4054/4054617.png'; const _imagePlaceholder = 'https://cdn-icons-png.flaticon.com/512/4054/4054617.png';
extension CharacterDataDtoToModel on CharactersDataDto { extension CharacterDataDtoToModel on CharactersDataDto {
CardData toDomain() => CardData( CardData toDomain() => CardData(
attributes?.name ?? 'UNKNOWN', attributes?.name ?? 'UNKNOWN',
imgUrl: attributes?.image ?? _imagePlaceholder, imgUrl: attributes?.image ?? _imagePlaceholder,
description: _makeDescription(attributes?.born, attributes?.died), description: _makeDescription(attributes?.born, attributes?.died),
); );
String _makeDescription(String? born, String? died){ String _makeDescription(String? born, String? died) {
return born != null && died != null return born != null && died != null
? '$born - $died' ? '$born - $died'
: born != null : born != null
? 'born: $born' ? 'born: $born'
: died != null : died != null
? 'died: $died' ? 'died: $died'
: ''; : '';
} }
} }
extension CharactersDtoToModel on CharactersDto { extension CharactersDtoToModel on CharactersDto {
HomeData toDomain() => HomeData( HomeData toDomain() => HomeData(
data: data?.map((e) => e.toDomain()).toList(), data: data?.map((e) => e.toDomain()).toList(),
nextPage: meta?.pagination?.next, nextPage: meta?.pagination?.next,
); );
} }

View File

@ -4,8 +4,8 @@ class CardData {
final String? imgUrl; final String? imgUrl;
CardData( CardData(
this.text, { this.text, {
required this.description, required this.description,
this.imgUrl, this.imgUrl,
}); });
} }

View File

@ -14,20 +14,19 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
title: 'Flutter Demo', title: 'Potter App',
theme: ThemeData( theme: ThemeData(
// colorScheme: ColorScheme.fromSeed(seedColor: Colors.black), colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), primarySwatch: Colors.orange,
useMaterial3: true, scaffoldBackgroundColor: Colors.white,
), useMaterial3: true,
home: RepositoryProvider<PotterRepository>( ),
lazy: true, home: RepositoryProvider<PotterRepository>(
create: (_) => PotterRepository(), lazy: true,
child: BlocProvider<HomeBloc>( create: (_) => PotterRepository(),
child: BlocProvider<HomeBloc>(
lazy: true, lazy: true,
create: (context) => HomeBloc(context.read<PotterRepository>()), create: (context) => HomeBloc(context.read<PotterRepository>()),
child: const MyHomePage(title: 'Potter API'), ),
), ));
)
);
} }
} }

View File

@ -0,0 +1,34 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:pmd_lab/components/resources.g.dart';
abstract class SvgObjects {
static void init() {
final pics = <String>[
R.ASSETS_SVG_RU_SVG,
R.ASSETS_SVG_UK_SVG,
];
for (final String p in pics) {
final loader = SvgAssetLoader(p);
svg.cache.putIfAbsent(loader.cacheKey(null), () => loader.loadBytes(null));
}
}
}
class SvgRu extends StatelessWidget {
const SvgRu({super.key});
@override
Widget build(BuildContext context) {
return SvgPicture.asset(R.ASSETS_SVG_RU_SVG);
}
}
class SvgUk extends StatelessWidget {
const SvgUk({super.key});
@override
Widget build(BuildContext context) {
return SvgPicture.asset(R.ASSETS_SVG_UK_SVG);
}
}

View File

@ -9,27 +9,28 @@ class DetailsPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar(), appBar: AppBar(),
body:Column( body: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.only(bottom: 16),
child: Image.network(data.imgUrl ?? '',), child: Image.network(
), data.imgUrl ?? '',
Padding( ),
padding: const EdgeInsets.only(bottom: 4), ),
child: Text( Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Text(
data.text, data.text,
style: Theme.of(context).textTheme.headlineLarge, style: Theme.of(context).textTheme.headlineLarge,
),
), ),
), Text(
Text(
data.description, data.description,
style: Theme.of(context).textTheme.bodyLarge, style: Theme.of(context).textTheme.bodyLarge,
) )
], ],
) ));
);
} }
} }

View File

@ -36,6 +36,4 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
error: error, error: error,
)); ));
} }
} }

View File

@ -1,11 +1,9 @@
class HomeEvent { class HomeEvent {
const HomeEvent(); const HomeEvent();
} }
class HomeLoadDataEvent extends HomeEvent{ class HomeLoadDataEvent extends HomeEvent {
final String? search; final String? search;
final int? nextPage; final int? nextPage;
const HomeLoadDataEvent({this.search, this.nextPage}); const HomeLoadDataEvent({this.search, this.nextPage});
}
}

View File

@ -34,11 +34,9 @@ class HomeState extends Equatable {
@override @override
List<Object?> get props => [ List<Object?> get props => [
data, data,
isLoading, isLoading,
isPaginationLoading, isPaginationLoading,
error, error,
]; ];
} }

View File

@ -72,8 +72,7 @@ class _$HomeStateCWProxyImpl implements _$HomeStateCWProxy {
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: isLoading as bool, : isLoading as bool,
isPaginationLoading: isPaginationLoading:
isPaginationLoading == const $CopyWithPlaceholder() || isPaginationLoading == const $CopyWithPlaceholder() || isPaginationLoading == null
isPaginationLoading == null
? _value.isPaginationLoading ? _value.isPaginationLoading
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: isPaginationLoading as bool, : isPaginationLoading as bool,

View File

@ -10,20 +10,20 @@ class _Card extends StatefulWidget {
final VoidCallback? onTap; final VoidCallback? onTap;
const _Card( const _Card(
this.text, { this.text, {
required this.description, required this.description,
this.imgUrl, this.imgUrl,
this.onLike, this.onLike,
this.onTap, this.onTap,
}); });
factory _Card.fromData(CardData data, {OnLikeCallBack onLike, VoidCallback? onTap}) => _Card( factory _Card.fromData(CardData data, {OnLikeCallBack onLike, VoidCallback? onTap}) => _Card(
data.text, data.text,
description: data.description, description: data.description,
imgUrl: data.imgUrl, imgUrl: data.imgUrl,
onLike: onLike, onLike: onLike,
onTap: onTap, onTap: onTap,
); );
@override @override
State<_Card> createState() => _CardState(); State<_Card> createState() => _CardState();
@ -38,81 +38,82 @@ class _CardState extends State<_Card> {
onTap: widget.onTap, onTap: widget.onTap,
child: Container( child: Container(
margin: const EdgeInsets.only(bottom: 20), margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration( decoration:
color: Colors.white, BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [
borderRadius: BorderRadius.circular(20), BoxShadow(
boxShadow: [ color: Colors.black.withOpacity(0.1),
BoxShadow( spreadRadius: 1,
color: Colors.black.withOpacity(0.1), offset: const Offset(0, 0),
spreadRadius: 1, blurRadius: 15,
offset: const Offset(0, 0), )
blurRadius: 15, ]),
) child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
]), Stack(children: [
child: Column( ClipRRect(
crossAxisAlignment: CrossAxisAlignment.stretch, borderRadius: const BorderRadius.only(
children: [ topLeft: Radius.circular(20), topRight: Radius.circular(20)),
Stack( child: Image.network(
children: [ widget.imgUrl ?? '',
ClipRRect( errorBuilder: (_, __, ___) => const Placeholder(),
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)), height: 370,
child: Image.network( alignment: Alignment.topCenter,
widget.imgUrl ?? '', fit: BoxFit.cover,
errorBuilder: (_, __, ___) => const Placeholder(), width: double.infinity,
height: 370, ),
alignment: Alignment.topCenter, ),
fit: BoxFit.cover, ]),
width: double.infinity, Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Text(
widget.text,
style: const TextStyle(
color: Color(0xff4c4c4c),
fontSize: 30,
fontWeight: FontWeight.bold,
), ),
), ),
]
),
Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom:10),
child: Text(
widget.text,
style: const TextStyle(
color: Color(0xff4c4c4c),
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
),
Text(
widget.description,
style: const TextStyle(
color: Color(0xff9c9c9c),
fontSize: 20,
fontWeight: FontWeight.normal,
),
),
Padding(
padding: const EdgeInsets.only(top:10),
child: GestureDetector(
onTap:(){
setState(() {
isLiked = !isLiked;
});
widget.onLike?.call(widget.text, isLiked);
},
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: isLiked
? const Icon(Icons.favorite, color: Colors.redAccent,key: ValueKey<int>(0),)
: const Icon(Icons.favorite_border, key:ValueKey<int>(1),),
),
)
)
],
), ),
), Text(
]), widget.description,
style: const TextStyle(
color: Color(0xff9c9c9c),
fontSize: 20,
fontWeight: FontWeight.normal,
),
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: GestureDetector(
onTap: () {
setState(() {
isLiked = !isLiked;
});
widget.onLike?.call(widget.text, isLiked);
},
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: isLiked
? const Icon(
Icons.favorite,
color: Colors.redAccent,
key: ValueKey<int>(0),
)
: const Icon(
Icons.favorite_border,
key: ValueKey<int>(1),
),
),
))
],
),
),
]),
), ),
); );
} }
} }

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pmd_lab/components/utils/debounce.dart'; import 'package:pmd_lab/components/utils/debounce.dart';
import 'package:pmd_lab/domain/models/card.dart'; import 'package:pmd_lab/domain/models/card.dart';
import 'package:pmd_lab/presentation/common/svg_objects.dart';
import 'package:pmd_lab/presentation/details_page/details_page.dart'; import 'package:pmd_lab/presentation/details_page/details_page.dart';
import 'package:pmd_lab/presentation/home_page/bloc/bloc.dart'; import 'package:pmd_lab/presentation/home_page/bloc/bloc.dart';
import 'package:pmd_lab/presentation/home_page/bloc/events.dart'; import 'package:pmd_lab/presentation/home_page/bloc/events.dart';
@ -12,68 +13,21 @@ import 'package:pmd_lab/repositories/mock_repository.dart';
import 'package:pmd_lab/repositories/potter_repository.dart'; import 'package:pmd_lab/repositories/potter_repository.dart';
part 'card.dart'; part 'card.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// colorScheme: ColorScheme.fromSeed(seedColor: Colors.black), colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter rocks!'),
);
}
}
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title}); const MyHomePage({super.key});
final String title;
@override @override
State<MyHomePage> createState() => _MyHomePageState(); State<MyHomePage> createState() => _MyHomePageState();
} }
class _MyHomePageState extends State<MyHomePage> { class _MyHomePageState extends State<MyHomePage> {
final Color _color = Colors.orangeAccent;
@override
void initState(){
WidgetsBinding.instance.addPostFrameCallback( (_) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Hello', style: Theme
.of(context)
.textTheme
.bodyLarge,),
backgroundColor: Colors.orangeAccent,
duration: const Duration(seconds: 1),
));
});
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return const Scaffold(body: Body());
appBar: AppBar(
backgroundColor: _color,
title: Text(widget.title),
),
body: const Body(),
);
} }
} }
class Body extends StatefulWidget { class Body extends StatefulWidget {
const Body({super.key}); const Body({super.key});
@override @override
State<Body> createState() => _BodyState(); State<Body> createState() => _BodyState();
} }
@ -86,12 +40,15 @@ class _BodyState extends State<Body> {
@override @override
void initState() { void initState() {
SvgObjects.init();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<HomeBloc>().add(const HomeLoadDataEvent()); context.read<HomeBloc>().add(const HomeLoadDataEvent());
}); });
scrollController.addListener(_onNextPageListener); scrollController.addListener(_onNextPageListener);
super.initState(); super.initState();
} }
void _onNextPageListener() { void _onNextPageListener() {
if (scrollController.offset > scrollController.position.maxScrollExtent) { if (scrollController.offset > scrollController.position.maxScrollExtent) {
final bloc = context.read<HomeBloc>(); final bloc = context.read<HomeBloc>();
@ -103,8 +60,9 @@ class _BodyState extends State<Body> {
} }
} }
} }
@override @override
void dispose(){ void dispose() {
searchController.dispose(); searchController.dispose();
scrollController.dispose(); scrollController.dispose();
@ -113,7 +71,6 @@ class _BodyState extends State<Body> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
child: Column( child: Column(
@ -130,31 +87,32 @@ class _BodyState extends State<Body> {
BlocBuilder<HomeBloc, HomeState>( BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) => state.error != null builder: (context, state) => state.error != null
? Text( ? Text(
state.error ?? '', state.error ?? '',
style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: Colors.red), style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: Colors.red),
) )
: state.isLoading : state.isLoading
? const CircularProgressIndicator() ? const CircularProgressIndicator()
: Expanded( : Expanded(
child: RefreshIndicator( child: RefreshIndicator(
onRefresh: _onRefresh, onRefresh: _onRefresh,
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: state.data?.data?.length ?? 0, itemCount: state.data?.data?.length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final data = state.data?.data?[index]; final data = state.data?.data?[index];
return data != null return data != null
? _Card.fromData( ? _Card.fromData(
data, data,
onLike: (title, isLiked) => _showSnackBar(context, title, isLiked), onLike: (title, isLiked) =>
onTap: () => _navToDetails(context, data), _showSnackBar(context, title, isLiked),
) onTap: () => _navToDetails(context, data),
: const SizedBox.shrink(); )
}, : const SizedBox.shrink();
), // ListView.builder },
), // RefreshIndicator ), // ListView.builder
), // Expanded ), // RefreshIndicator
), // Expanded
), // BlocBuilder ), // BlocBuilder
BlocBuilder<HomeBloc, HomeState>( BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) => state.isPaginationLoading builder: (context, state) => state.isPaginationLoading
@ -171,10 +129,8 @@ class _BodyState extends State<Body> {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text( content: Text(
'Article $title ${isLiked ? 'liked!' : 'disliked :('}', 'Article $title ${isLiked ? 'liked!' : 'disliked :('}',
style: Theme style: Theme.of(context).textTheme.bodyLarge,
.of(context) ),
.textTheme
.bodyLarge,),
backgroundColor: Colors.orangeAccent, backgroundColor: Colors.orangeAccent,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
)); ));
@ -192,5 +148,4 @@ class _BodyState extends State<Body> {
context.read<HomeBloc>().add(HomeLoadDataEvent(search: searchController.text)); context.read<HomeBloc>().add(HomeLoadDataEvent(search: searchController.text));
return Future.value(null); return Future.value(null);
} }
}
}

View File

@ -1,4 +1,3 @@
import 'package:pmd_lab/domain/models/home.dart'; import 'package:pmd_lab/domain/models/home.dart';
typedef OnErrorCallback = void Function(String? error); typedef OnErrorCallback = void Function(String? error);
@ -6,4 +5,3 @@ typedef OnErrorCallback = void Function(String? error);
abstract class ApiInterface { abstract class ApiInterface {
Future<HomeData?> loadData({OnErrorCallback? onError}); Future<HomeData?> loadData({OnErrorCallback? onError});
} }

View File

@ -4,8 +4,8 @@ import 'package:pmd_lab/domain/models/card.dart';
class MockRepository extends ApiInterface { class MockRepository extends ApiInterface {
@override @override
Future <HomeData?> loadData({OnErrorCallback? onError}) async { Future<HomeData?> loadData({OnErrorCallback? onError}) async {
return HomeData(); return HomeData();
// return [ // return [
// CardData( // CardData(
// 'Какая-то новость', // 'Какая-то новость',
@ -25,6 +25,6 @@ class MockRepository extends ApiInterface {
// imgUrl: // imgUrl:
// "https://universal.revengel.ru/assets/cache_image/images/services/1_731x487_1cb.png", // "https://universal.revengel.ru/assets/cache_image/images/services/1_731x487_1cb.png",
// ) // )
//]; //];
} }
} }

View File

@ -8,7 +8,7 @@ import 'package:pmd_lab/domain/models/home.dart';
import 'package:pmd_lab/repositories/api_interface.dart'; import 'package:pmd_lab/repositories/api_interface.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart';
class PotterRepository extends ApiInterface{ class PotterRepository extends ApiInterface {
static final Dio _dio = Dio() static final Dio _dio = Dio()
..interceptors.add(PrettyDioLogger( ..interceptors.add(PrettyDioLogger(
requestHeader: true, requestHeader: true,
@ -39,10 +39,9 @@ class PotterRepository extends ApiInterface{
final CharactersDto dto = CharactersDto.fromJson(response.data as Map<String, dynamic>); final CharactersDto dto = CharactersDto.fromJson(response.data as Map<String, dynamic>);
final HomeData data = dto.toDomain(); final HomeData data = dto.toDomain();
return data; return data;
} on DioException catch (e) { } on DioException catch (e) {
onError?.call(e.error?.toString()); onError?.call(e.error?.toString());
return null; return null;
} }
} }
} }

View File

@ -22,6 +22,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.7.0" version: "6.7.0"
archive:
dependency: transitive
description:
name: archive
sha256: "08064924cbf0ab88280a0c3f60db9dd24fec693927e725ecb176f16c629d1cb8"
url: "https://pub.dev"
source: hosted
version: "4.0.1"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -134,6 +142,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.3" version: "2.0.3"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.2"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -238,6 +254,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
file: file:
dependency: transitive dependency: transitive
description: description:
@ -267,19 +291,45 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.1.6" version: "8.1.6"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev"
source: hosted
version: "0.13.1"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "2.0.3"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
url: "https://pub.dev"
source: hosted
version: "2.0.7"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client: frontend_server_client:
dependency: transitive dependency: transitive
description: description:
@ -304,6 +354,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.3.2"
http:
dependency: transitive
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev"
source: hosted
version: "1.2.2"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -320,6 +378,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
image:
dependency: transitive
description:
name: image
sha256: "20842a5ad1555be624c314b0c0cc0566e8ece412f61e859a42efeb6d4101a26c"
url: "https://pub.dev"
source: hosted
version: "4.5.0"
intl:
dependency: "direct main"
description:
name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev"
source: hosted
version: "0.19.0"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -380,10 +454,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "2.1.1"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -456,6 +530,62 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.0" version: "1.9.0"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev"
source: hosted
version: "2.3.0"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "6.0.2"
platform:
dependency: transitive
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev"
source: hosted
version: "3.1.6"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -464,6 +594,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.1" version: "1.5.1"
posix:
dependency: transitive
description:
name: posix
sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
url: "https://pub.dev"
source: hosted
version: "6.0.1"
pretty_dio_logger: pretty_dio_logger:
dependency: "direct main" dependency: "direct main"
description: description:
@ -496,6 +634,62 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
url: "https://pub.dev"
source: hosted
version: "2.2.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
url: "https://pub.dev"
source: hosted
version: "2.4.2"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
@ -605,6 +799,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "27d5fefe86fb9aace4a9f8375b56b3c292b64d8c04510df230f849850d912cb7"
url: "https://pub.dev"
source: hosted
version: "1.1.15"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb"
url: "https://pub.dev"
source: hosted
version: "1.1.12"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad"
url: "https://pub.dev"
source: hosted
version: "1.1.16"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -653,6 +871,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "3.0.1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
@ -663,4 +897,4 @@ packages:
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.5.3 <4.0.0" dart: ">=3.5.3 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54" flutter: ">=3.24.0"

View File

@ -1,98 +1,54 @@
name: pmd_lab name: pmd_lab
description: "A new Flutter project." description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: ^3.5.3 sdk: ^3.5.3
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
# Виджеты
cupertino_icons: ^1.0.2
flutter_svg: 2.0.7
# The following adds the Cupertino Icons font to your application. # Сетевое взаимодействие
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
json_annotation: ^4.8.1 json_annotation: ^4.8.1
dio: ^5.4.2+1 dio: ^5.4.2+1
pretty_dio_logger: ^1.3.1 pretty_dio_logger: ^1.3.1
# BLoC
equatable: ^2.0.5 equatable: ^2.0.5
flutter_bloc: ^8.1.5 flutter_bloc: ^8.1.5
copy_with_extension_gen: ^5.0.4 copy_with_extension_gen: ^5.0.4
# Localization
flutter_localizations:
sdk: flutter
intl: ^0.19.0
shared_preferences: 2.2.3
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0
# Иконки
flutter_launcher_icons: 0.13.1
# Сетевое взаимодействие
build_runner: ^2.4.9 build_runner: ^2.4.9
json_serializable: ^6.7.1 json_serializable: ^6.7.1
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^4.0.0
# For information on the generic Dart part of this file, see the flutter_icons:
# following page: https://dart.dev/tools/pub/pubspec android: "ic_launcher"
image_path: "assets/wp.png"
min_sdk_android: 21
# The following section is specific to Flutter packages.
flutter: flutter:
generate: true
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true uses-material-design: true
assets:
# To add assets to your application, add an assets section, like this: - assets/svg/
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package