lab7 done
This commit is contained in:
parent
1d3c9fd4f4
commit
197bc0cca6
@ -18,8 +18,18 @@ class CatDataDto {
|
||||
final String? name;
|
||||
final String? origin;
|
||||
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);
|
||||
}
|
||||
|
@ -17,4 +17,8 @@ CatDataDto _$CatDataDtoFromJson(Map<String, dynamic> json) => CatDataDto(
|
||||
name: json['name'] as String?,
|
||||
origin: json['origin'] 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(
|
||||
name ?? 'UNKNOWN',
|
||||
imageUrl: imageLink ?? _imagePlaceholder,
|
||||
descriptionText: _makeDescriptionText(origin, length),
|
||||
descriptionText: _makeDescriptionText(origin, length, minWeight,
|
||||
maxWeight, minLifeExpectancy, maxLifeExpectancy),
|
||||
id: name,
|
||||
);
|
||||
|
||||
String _makeDescriptionText(String? origin, String? length) {
|
||||
return origin != null || length != null
|
||||
? 'Origin: $origin \nLength: $length'
|
||||
: origin != null
|
||||
? 'Origin: $origin'
|
||||
: length != null
|
||||
? 'Length: $length'
|
||||
String _makeDescriptionText(String? origin, String? length, int? minWeight,
|
||||
int? maxWeight, int? minLifeExpectancy, int? maxLifeExpectancy) {
|
||||
String description = '';
|
||||
|
||||
if (origin != null) {
|
||||
description += '\nOrigin: $origin';
|
||||
}
|
||||
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,
|
||||
String? q,
|
||||
int offset = 0,
|
||||
//int minWeight=1,
|
||||
}) async {
|
||||
try {
|
||||
const String url = '/v1/cats?min_weight=1';
|
||||
@ -28,7 +27,6 @@ class CatsRepository extends ApiInterface {
|
||||
final Response<dynamic> response = await _dio.get<dynamic>(
|
||||
url,
|
||||
queryParameters: {
|
||||
//'min_weight': minWeight,
|
||||
'name': q,
|
||||
'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 'package:flutter/material.dart';
|
||||
@ -65,7 +31,7 @@ class MyApp extends StatelessWidget {
|
||||
supportedLocales: AppLocale.supportedLocales,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.orangeAccent),
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurpleAccent),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: RepositoryProvider<CatsRepository>(
|
||||
|
@ -11,9 +11,9 @@ class DetailsPage extends StatelessWidget {
|
||||
return Scaffold(
|
||||
appBar: AppBar(),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(
|
||||
child: Image.network(
|
||||
@ -21,7 +21,7 @@ class DetailsPage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
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),
|
||||
Text(data.descriptionText, style: const TextStyle(fontSize: 22, color: Colors.black87)),
|
||||
// Add more details here as needed
|
||||
|
@ -29,7 +29,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
final updatedData = event.nextPage != null && data != null
|
||||
? HomeData(
|
||||
data: [...state.data?.data ?? [], ...data.data!],
|
||||
nextPage: (event.nextPage! + 1),
|
||||
nextPage: (event.nextPage! + 20),
|
||||
)
|
||||
: data;
|
||||
|
||||
|
@ -46,94 +46,10 @@ class _Card extends StatelessWidget {
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(16),
|
||||
constraints: const BoxConstraints(minHeight: 240),
|
||||
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),
|
||||
constraints: const BoxConstraints(minHeight: 200),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white70,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(color: Colors.grey),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(.5),
|
||||
@ -148,33 +64,34 @@ class _Card extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(20),
|
||||
topLeft: Radius.circular(20),
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(20)
|
||||
),
|
||||
child: SizedBox(
|
||||
height: double.infinity,
|
||||
width: 140,
|
||||
width: 180,
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Image.network(
|
||||
widget.imageUrl ?? '',
|
||||
imageUrl ?? '',
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __, ___) => const Placeholder(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
padding: const EdgeInsets.only(left: 18.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.text,
|
||||
style: TextStyle(fontSize: 23),
|
||||
),
|
||||
Text(
|
||||
widget.descriptionText,
|
||||
style: TextStyle(fontSize: 19),
|
||||
text,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -183,20 +100,11 @@ class _Card extends StatelessWidget {
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 8.0,
|
||||
right: 16.0,
|
||||
bottom: 16.0,
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 5, right: 16, bottom: 16),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isLiked = !isLiked;
|
||||
});
|
||||
widget.onLike?.call(widget.text, isLiked);
|
||||
},
|
||||
onTap: () => onLike?.call(id, text, isLiked),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: isLiked
|
||||
? const Icon(
|
||||
Icons.favorite,
|
||||
@ -216,5 +124,5 @@ class _Card extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +177,11 @@ class _BodyState extends State<_Body> {
|
||||
nextPage: nextPage,
|
||||
));
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.deepPurple[200],
|
||||
foregroundColor: Colors.black87,
|
||||
textStyle: TextStyle(fontSize: 20),
|
||||
),
|
||||
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() {
|
||||
context.read<HomeBloc>().add(HomeLoadDataEvent(search: searchController.text));
|
||||
@ -267,7 +219,7 @@ class _BodyState extends State<_Body> {
|
||||
'You ${isLiked ? 'like!' : 'disliked :('} $title ',
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: Colors.deepPurpleAccent[100],
|
||||
duration: const Duration(seconds: 1),
|
||||
));
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user