lab7 done
This commit is contained in:
parent
1d3c9fd4f4
commit
197bc0cca6
@ -18,8 +18,18 @@ class CatDataDto {
|
|||||||
final String? name;
|
final String? name;
|
||||||
final String? origin;
|
final String? origin;
|
||||||
final String? length;
|
final String? length;
|
||||||
|
@JsonKey(name: 'min_weight')
|
||||||
|
final int? minWeight;
|
||||||
|
@JsonKey(name: 'max_weight')
|
||||||
|
final int? maxWeight;
|
||||||
|
@JsonKey(name: 'min_life_expectancy')
|
||||||
|
final int? minLifeExpectancy;
|
||||||
|
@JsonKey(name: 'max_life_expectancy')
|
||||||
|
final int? maxLifeExpectancy;
|
||||||
|
|
||||||
const CatDataDto({this.imageLink, this.name, this.origin, this.length});
|
|
||||||
|
const CatDataDto({this.imageLink, this.name, this.origin, this.length,
|
||||||
|
this.minWeight, this.maxWeight, this.minLifeExpectancy, this.maxLifeExpectancy});
|
||||||
|
|
||||||
factory CatDataDto.fromJson(Map<String, dynamic> json) => _$CatDataDtoFromJson(json);
|
factory CatDataDto.fromJson(Map<String, dynamic> json) => _$CatDataDtoFromJson(json);
|
||||||
}
|
}
|
||||||
|
@ -17,4 +17,8 @@ CatDataDto _$CatDataDtoFromJson(Map<String, dynamic> json) => CatDataDto(
|
|||||||
name: json['name'] as String?,
|
name: json['name'] as String?,
|
||||||
origin: json['origin'] as String?,
|
origin: json['origin'] as String?,
|
||||||
length: json['length'] as String?,
|
length: json['length'] as String?,
|
||||||
|
minWeight: (json['min_weight'] as num?)?.toInt(),
|
||||||
|
maxWeight: (json['min_weight'] as num?)?.toInt(),
|
||||||
|
minLifeExpectancy: (json['min_life_expectancy'] as num?)?.toInt(),
|
||||||
|
maxLifeExpectancy: (json['max_life_expectancy'] as num?)?.toInt(),
|
||||||
);
|
);
|
||||||
|
@ -16,16 +16,38 @@ extension CatDataDtoToModel on CatDataDto {
|
|||||||
CardData toDomain() => CardData(
|
CardData toDomain() => CardData(
|
||||||
name ?? 'UNKNOWN',
|
name ?? 'UNKNOWN',
|
||||||
imageUrl: imageLink ?? _imagePlaceholder,
|
imageUrl: imageLink ?? _imagePlaceholder,
|
||||||
descriptionText: _makeDescriptionText(origin, length),
|
descriptionText: _makeDescriptionText(origin, length, minWeight,
|
||||||
|
maxWeight, minLifeExpectancy, maxLifeExpectancy),
|
||||||
|
id: name,
|
||||||
);
|
);
|
||||||
|
|
||||||
String _makeDescriptionText(String? origin, String? length) {
|
String _makeDescriptionText(String? origin, String? length, int? minWeight,
|
||||||
return origin != null || length != null
|
int? maxWeight, int? minLifeExpectancy, int? maxLifeExpectancy) {
|
||||||
? 'Origin: $origin \nLength: $length'
|
String description = '';
|
||||||
: origin != null
|
|
||||||
? 'Origin: $origin'
|
if (origin != null) {
|
||||||
: length != null
|
description += '\nOrigin: $origin';
|
||||||
? 'Length: $length'
|
}
|
||||||
|
if (length != null) {
|
||||||
|
description += '\nLength: $length';
|
||||||
|
}
|
||||||
|
|
||||||
|
minWeight != null && maxWeight != null
|
||||||
|
? description += '\nWeight: $minWeight - $maxWeight pounds'
|
||||||
|
: minWeight != null
|
||||||
|
? description += '\nMin weight: $minWeight pounds'
|
||||||
|
: maxWeight != null
|
||||||
|
? description += '\nMax weight: $maxWeight pounds'
|
||||||
|
: '';
|
||||||
|
|
||||||
|
minLifeExpectancy != null && maxLifeExpectancy != null
|
||||||
|
? description += '\nLife expectancy: $minLifeExpectancy - $maxLifeExpectancy years'
|
||||||
|
: minLifeExpectancy != null
|
||||||
|
? description += '\nMin life expectancy: $minLifeExpectancy years'
|
||||||
|
: maxLifeExpectancy != null
|
||||||
|
? description += '\nMax life expectancy: $maxLifeExpectancy years'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
return description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ class CatsRepository extends ApiInterface {
|
|||||||
OnErrorCallback? onError,
|
OnErrorCallback? onError,
|
||||||
String? q,
|
String? q,
|
||||||
int offset = 0,
|
int offset = 0,
|
||||||
//int minWeight=1,
|
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
const String url = '/v1/cats?min_weight=1';
|
const String url = '/v1/cats?min_weight=1';
|
||||||
@ -28,7 +27,6 @@ class CatsRepository extends ApiInterface {
|
|||||||
final Response<dynamic> response = await _dio.get<dynamic>(
|
final Response<dynamic> response = await _dio.get<dynamic>(
|
||||||
url,
|
url,
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
//'min_weight': minWeight,
|
|
||||||
'name': q,
|
'name': q,
|
||||||
'offset': offset,
|
'offset': offset,
|
||||||
},
|
},
|
||||||
|
@ -1,37 +1,3 @@
|
|||||||
/*import 'package:flutter/material.dart';
|
|
||||||
import 'package:pmu/data/repositories/cats_repository.dart';
|
|
||||||
import 'package:pmu/presentation/home_page/home_page.dart';
|
|
||||||
import 'package:pmu/presentation/home_page/bloc/bloc.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.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.deepPurple.shade300),
|
|
||||||
useMaterial3: true,
|
|
||||||
),
|
|
||||||
home: RepositoryProvider<CatsRepository>(
|
|
||||||
lazy: true,
|
|
||||||
create: (_) => CatsRepository(),
|
|
||||||
child: BlocProvider<HomeBloc>(
|
|
||||||
lazy: false,
|
|
||||||
create: (context) => HomeBloc(context.read<CatsRepository>()),
|
|
||||||
child: const MyHomePage(title: 'Энциклопедия кошек'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -65,7 +31,7 @@ class MyApp extends StatelessWidget {
|
|||||||
supportedLocales: AppLocale.supportedLocales,
|
supportedLocales: AppLocale.supportedLocales,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.orangeAccent),
|
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurpleAccent),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
home: RepositoryProvider<CatsRepository>(
|
home: RepositoryProvider<CatsRepository>(
|
||||||
|
@ -11,9 +11,9 @@ class DetailsPage extends StatelessWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(),
|
appBar: AppBar(),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: Image.network(
|
child: Image.network(
|
||||||
@ -21,7 +21,7 @@ class DetailsPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Text(data.text, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
Text(data.text, style: const TextStyle(fontSize: 26, fontWeight: FontWeight.w400)),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text(data.descriptionText, style: const TextStyle(fontSize: 22, color: Colors.black87)),
|
Text(data.descriptionText, style: const TextStyle(fontSize: 22, color: Colors.black87)),
|
||||||
// Add more details here as needed
|
// Add more details here as needed
|
||||||
|
@ -29,7 +29,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
final updatedData = event.nextPage != null && data != null
|
final updatedData = event.nextPage != null && data != null
|
||||||
? HomeData(
|
? HomeData(
|
||||||
data: [...state.data?.data ?? [], ...data.data!],
|
data: [...state.data?.data ?? [], ...data.data!],
|
||||||
nextPage: (event.nextPage! + 1),
|
nextPage: (event.nextPage! + 20),
|
||||||
)
|
)
|
||||||
: data;
|
: data;
|
||||||
|
|
||||||
|
@ -46,94 +46,10 @@ class _Card extends StatelessWidget {
|
|||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.all(16),
|
margin: const EdgeInsets.all(16),
|
||||||
constraints: const BoxConstraints(minHeight: 240),
|
constraints: const BoxConstraints(minHeight: 200),
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.grey,
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.grey.withOpacity(.5),
|
|
||||||
spreadRadius: 4,
|
|
||||||
offset: const Offset(0, 5),
|
|
||||||
blurRadius: 8,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.bottomRight,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 8, right: 16, bottom: 16, top: 10),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () => onLike?.call(id, text, isLiked),
|
|
||||||
child: AnimatedSwitcher(
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
child: isLiked
|
|
||||||
? const Icon(
|
|
||||||
Icons.favorite,
|
|
||||||
color: Colors.redAccent,
|
|
||||||
key: ValueKey<int>(0),
|
|
||||||
)
|
|
||||||
: const Icon(
|
|
||||||
Icons.favorite_border,
|
|
||||||
key: ValueKey<int>(1),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(20),
|
|
||||||
topRight: Radius.circular(20),
|
|
||||||
),
|
|
||||||
child: SizedBox(
|
|
||||||
height: 160,
|
|
||||||
width: double.infinity,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Positioned.fill(
|
|
||||||
child: Image.network(
|
|
||||||
imageUrl ?? '',
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
errorBuilder: (_, __, ___) => const Placeholder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
text,
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/*Widget build(BuildContext context) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: onTap,
|
|
||||||
child: Container(
|
|
||||||
margin: const EdgeInsets.all(16),
|
|
||||||
constraints: const BoxConstraints(minHeight: 140),
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white70,
|
color: Colors.white70,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
border: Border.all(color: Colors.grey),
|
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.grey.withOpacity(.5),
|
color: Colors.grey.withOpacity(.5),
|
||||||
@ -148,33 +64,34 @@ class _Card extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.all(
|
||||||
bottomLeft: Radius.circular(20),
|
Radius.circular(20)
|
||||||
topLeft: Radius.circular(20),
|
|
||||||
),
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
width: 140,
|
width: 180,
|
||||||
child: Image.network(
|
child: Stack(
|
||||||
widget.imageUrl ?? '',
|
children: [
|
||||||
fit: BoxFit.cover,
|
Positioned.fill(
|
||||||
errorBuilder: (_, __, ___) => const Placeholder(),
|
child: Image.network(
|
||||||
|
imageUrl ?? '',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (_, __, ___) => const Placeholder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 16.0),
|
padding: const EdgeInsets.only(left: 18.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
widget.text,
|
text,
|
||||||
style: TextStyle(fontSize: 23),
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
),
|
|
||||||
Text(
|
|
||||||
widget.descriptionText,
|
|
||||||
style: TextStyle(fontSize: 19),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -183,30 +100,21 @@ class _Card extends StatelessWidget {
|
|||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomRight,
|
alignment: Alignment.bottomRight,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(left: 5, right: 16, bottom: 16),
|
||||||
left: 8.0,
|
|
||||||
right: 16.0,
|
|
||||||
bottom: 16.0,
|
|
||||||
),
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () => onLike?.call(id, text, isLiked),
|
||||||
setState(() {
|
|
||||||
isLiked = !isLiked;
|
|
||||||
});
|
|
||||||
widget.onLike?.call(widget.text, isLiked);
|
|
||||||
},
|
|
||||||
child: AnimatedSwitcher(
|
child: AnimatedSwitcher(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 200),
|
||||||
child: isLiked
|
child: isLiked
|
||||||
? const Icon(
|
? const Icon(
|
||||||
Icons.favorite,
|
Icons.favorite,
|
||||||
color: Colors.purpleAccent,
|
color: Colors.purpleAccent,
|
||||||
key: ValueKey<int>(0),
|
key: ValueKey<int>(0),
|
||||||
)
|
)
|
||||||
: const Icon(
|
: const Icon(
|
||||||
Icons.favorite_border,
|
Icons.favorite_border,
|
||||||
key: ValueKey<int>(1),
|
key: ValueKey<int>(1),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -216,5 +124,5 @@ class _Card extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,6 +177,11 @@ class _BodyState extends State<_Body> {
|
|||||||
nextPage: nextPage,
|
nextPage: nextPage,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.deepPurple[200],
|
||||||
|
foregroundColor: Colors.black87,
|
||||||
|
textStyle: TextStyle(fontSize: 20),
|
||||||
|
),
|
||||||
child: Text(context.locale.next),
|
child: Text(context.locale.next),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -187,59 +192,6 @@ class _BodyState extends State<_Body> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/*Widget build(BuildContext context) {
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
child: CupertinoSearchTextField(
|
|
||||||
controller: searchController,
|
|
||||||
onChanged: (search) {
|
|
||||||
Debounce.run(() => context.read<HomeBloc>().add(HomeLoadDataEvent(search: search)));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
BlocBuilder<HomeBloc, HomeState>(
|
|
||||||
builder: (context, state) => state.error != null
|
|
||||||
? Text(
|
|
||||||
state.error ?? '',
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: Colors.red),
|
|
||||||
)
|
|
||||||
: state.isLoading
|
|
||||||
? const CircularProgressIndicator()
|
|
||||||
: Expanded(
|
|
||||||
child: RefreshIndicator(
|
|
||||||
onRefresh: _onRefresh,
|
|
||||||
child: ListView.builder(
|
|
||||||
controller: scrollController,
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
itemCount: state.data?.data?.length ?? 0,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final data = state.data?.data?[index];
|
|
||||||
return data != null
|
|
||||||
? _Card.fromData(
|
|
||||||
data,
|
|
||||||
onLike: (title, isLiked) =>
|
|
||||||
_showSnackBar(context, title, isLiked),
|
|
||||||
onTap: () => _navToDetails(context, data),
|
|
||||||
)
|
|
||||||
: const SizedBox.shrink();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
BlocBuilder<HomeBloc, HomeState>(
|
|
||||||
builder: (context, state) => state.isPaginationLoading
|
|
||||||
? const CircularProgressIndicator()
|
|
||||||
: const SizedBox.shrink(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
Future<void> _onRefresh() {
|
Future<void> _onRefresh() {
|
||||||
context.read<HomeBloc>().add(HomeLoadDataEvent(search: searchController.text));
|
context.read<HomeBloc>().add(HomeLoadDataEvent(search: searchController.text));
|
||||||
@ -267,7 +219,7 @@ class _BodyState extends State<_Body> {
|
|||||||
'You ${isLiked ? 'like!' : 'disliked :('} $title ',
|
'You ${isLiked ? 'like!' : 'disliked :('} $title ',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.deepPurpleAccent[100],
|
||||||
duration: const Duration(seconds: 1),
|
duration: const Duration(seconds: 1),
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user