lab7 done

This commit is contained in:
Dasha 2024-12-11 02:50:15 +04:00
parent 1d3c9fd4f4
commit 197bc0cca6
9 changed files with 84 additions and 224 deletions

View File

@ -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);
} }

View File

@ -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(),
); );

View File

@ -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;
} }
} }

View File

@ -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,
}, },

View File

@ -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>(

View File

@ -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

View File

@ -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;

View File

@ -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 {
), ),
), ),
); );
}*/ }
} }

View File

@ -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),
)); ));
}); });