lab5 вроде done

This commit is contained in:
Алексей Тихоненков 2024-12-11 06:12:20 +04:00
parent 0e8ce38c33
commit 76dcbb954b
5 changed files with 74 additions and 30 deletions

View File

@ -13,11 +13,11 @@ class QuotesDto {
@JsonSerializable(createToJson: false)
class QuoteDataDto {
final String? text;
final String? body;
final String? author;
final String? imageUrl;
const QuoteDataDto({this.text, this.author, this.imageUrl});
const QuoteDataDto({this.body, this.author, this.imageUrl});
factory QuoteDataDto.fromJson(Map<String, dynamic> json) => _$QuoteDataDtoFromJson(json);
}

View File

@ -13,7 +13,7 @@ QuotesDto _$QuotesDtoFromJson(Map<String, dynamic> json) => QuotesDto(
);
QuoteDataDto _$QuoteDataDtoFromJson(Map<String, dynamic> json) => QuoteDataDto(
text: json['text'] as String?,
body: json['body'] as String?,
author: json['author'] as String?,
imageUrl: json['imageUrl'] as String?,
);

View File

@ -6,7 +6,7 @@ const _imagePlaceholder =
extension QuoteDtoToModel on QuoteDataDto {
Quote toDomain() => Quote(
text ?? 'Без текста',
body ?? 'Без текста',
author ?? 'Неизвестный автор',
imageUrl ?? _imagePlaceholder,
);

View File

@ -13,19 +13,32 @@ class QuotesRepository extends ApiInterface {
requestBody: true,
))
..options.headers = {
'Authorization': 'Bearer 82ccaa45c8344de4ac008b2487d33361', // Add the API key here
'Authorization': 'Bearer 82ccaa45c8344de4ac008b2487d33361',
};
static const String _baseUrl = 'https://favqs.com/api';
@override
Future<List<Quote>?> loadData({String? q, OnErrorCallback? onError}) async {
Future<List<Quote>?> loadData({String? q, String? author, OnErrorCallback? onError}) async {
try {
final Map<String, dynamic> queryParams = {};
// Добавляем фильтрацию по тексту цитаты
if (q != null && q.isNotEmpty) {
queryParams['filter'] = q; // Фильтруем по слову
}
// Добавляем фильтрацию по автору
if (author != null && author.isNotEmpty) {
queryParams['type'] = 'author';
queryParams['filter'] = author;
}
const String url = '$_baseUrl/quotes';
final Response<dynamic> response = await _dio.get<Map<dynamic, dynamic>>(
url,
queryParameters: q != null ? {'filter[text_cont]': q} : null,
queryParameters: queryParams.isNotEmpty ? queryParams : null,
);
final QuotesDto dto = QuotesDto.fromJson(response.data as Map<String, dynamic>);
@ -37,3 +50,4 @@ class QuotesRepository extends ApiInterface {
}
}
}

View File

@ -44,48 +44,70 @@ class MyHomePage extends StatefulWidget {
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController searchController = TextEditingController();
final List<Quote> _quotes = [];
final List<Quote> _filteredQuotes = [];
final QuotesRepository _quotesRepository = QuotesRepository();
final TextEditingController searchController = TextEditingController();
final TextEditingController authorController = TextEditingController();
@override
void initState() {
super.initState();
_loadQuotes();
searchController.addListener(() {
_filterQuotes(searchController.text);
_loadQuotes();
});
authorController.addListener(() {
_loadQuotes();
});
}
// Метод для загрузки цитат с учетом обоих фильтров
Future<void> _loadQuotes() async {
final quotes = await _quotesRepository.loadData(onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Ошибка загрузки: $error')),
);
});
final query = searchController.text;
final author = authorController.text;
final quotes = await _quotesRepository.loadData(
q: query, // Поиск по цитате
author: author, // Поиск по автору
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Ошибка загрузки: $error')),
);
},
);
if (quotes != null) {
setState(() {
_quotes.clear();
_quotes.addAll(quotes);
_filteredQuotes.addAll(quotes);
_filterQuotes();
});
}
print('Загружено цитат: ${_quotes.length}');
print('Отфильтрованные цитаты: ${_filteredQuotes.length}');
}
void _filterQuotes(String query) {
// Фильтрация цитат по введенным значениям
void _filterQuotes() {
setState(() {
if (query.isEmpty) {
_filteredQuotes.clear();
_filteredQuotes.addAll(_quotes);
} else {
_filteredQuotes.clear();
_filteredQuotes.addAll(
_quotes.where((quote) =>
quote.text.toLowerCase().contains(query.toLowerCase()) ||
quote.author.toLowerCase().contains(query.toLowerCase())),
);
_filteredQuotes.clear(); // Очистите список фильтрации
_filteredQuotes.addAll(_quotes); // Изначально показываем все цитаты
// Применяем фильтрацию по цитате
if (searchController.text.isNotEmpty) {
_filteredQuotes.retainWhere((quote) =>
quote.text.toLowerCase().contains(searchController.text.toLowerCase()));
}
// Применяем фильтрацию по автору
if (authorController.text.isNotEmpty) {
_filteredQuotes.retainWhere((quote) =>
quote.author.toLowerCase().contains(authorController.text.toLowerCase()));
}
});
}
@ -95,8 +117,6 @@ class _MyHomePageState extends State<MyHomePage> {
return Scaffold(
appBar: AppBar(
title: const Text('Цитаты'),
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
foregroundColor: Theme.of(context).colorScheme.onPrimaryContainer,
),
body: Column(
children: [
@ -105,11 +125,21 @@ class _MyHomePageState extends State<MyHomePage> {
child: TextField(
controller: searchController,
decoration: const InputDecoration(
labelText: 'Поиск',
labelText: 'Поиск по цитате',
prefixIcon: Icon(Icons.search),
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: authorController,
decoration: const InputDecoration(
labelText: 'Поиск по автору',
prefixIcon: Icon(Icons.person),
),
),
),
Expanded(
child: _filteredQuotes.isEmpty
? const Center(
@ -121,7 +151,7 @@ class _MyHomePageState extends State<MyHomePage> {
: ListView.builder(
itemCount: _filteredQuotes.length,
itemBuilder: (context, index) {
final quote = _filteredQuotes[index];
final quote = _filteredQuotes[index]; // Используем _filteredQuotes для отображения
return Card(
margin: const EdgeInsets.symmetric(
vertical: 8.0,