184 lines
5.7 KiB
Dart
184 lines
5.7 KiB
Dart
|
import 'package:flutter/material.dart';
|
|||
|
import 'character.dart';
|
|||
|
import 'character_service.dart';
|
|||
|
import 'pages/CharacterDetailPage.dart';
|
|||
|
|
|||
|
void main() => runApp(MyApp());
|
|||
|
|
|||
|
class MyApp extends StatelessWidget {
|
|||
|
@override
|
|||
|
Widget build(BuildContext context) {
|
|||
|
return MaterialApp(
|
|||
|
title: 'Identity V Characters',
|
|||
|
home: MyHomePage(title: 'Персонажи Identity V'),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class MyHomePage extends StatefulWidget {
|
|||
|
MyHomePage({Key? key, required this.title}) : super(key: key);
|
|||
|
|
|||
|
final String title;
|
|||
|
|
|||
|
@override
|
|||
|
_MyHomePageState createState() => _MyHomePageState();
|
|||
|
}
|
|||
|
|
|||
|
class _MyHomePageState extends State<MyHomePage> {
|
|||
|
final CharacterService _characterService = CharacterService();
|
|||
|
late Future<List<Character>> _futureCharacters;
|
|||
|
final TextEditingController _searchController = TextEditingController();
|
|||
|
|
|||
|
@override
|
|||
|
void initState() {
|
|||
|
super.initState();
|
|||
|
_futureCharacters = _characterService.getCharacters();
|
|||
|
}
|
|||
|
|
|||
|
void _searchCharacters(String query) {
|
|||
|
setState(() {
|
|||
|
_futureCharacters = _characterService.getCharacters(search: query);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
@override
|
|||
|
Widget build(BuildContext context) {
|
|||
|
return Scaffold(
|
|||
|
appBar: AppBar(
|
|||
|
title: Text(widget.title),
|
|||
|
actions: [
|
|||
|
IconButton(
|
|||
|
icon: Icon(Icons.search),
|
|||
|
onPressed: () {
|
|||
|
showSearch(
|
|||
|
context: context,
|
|||
|
delegate: CharacterSearchDelegate(_searchCharacters),
|
|||
|
);
|
|||
|
},
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
body: FutureBuilder<List<Character>>(
|
|||
|
future: _futureCharacters,
|
|||
|
builder: (context, snapshot) {
|
|||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
|||
|
return Center(child: CircularProgressIndicator());
|
|||
|
} else if (snapshot.hasError) {
|
|||
|
return Center(child: Text('Ошибка: ${snapshot.error}'));
|
|||
|
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
|||
|
return Center(child: Text('Нет персонажей'));
|
|||
|
} else {
|
|||
|
final characters = snapshot.data!;
|
|||
|
|
|||
|
return ListView.builder(
|
|||
|
itemCount: characters.length,
|
|||
|
itemBuilder: (context, index) {
|
|||
|
final character = characters[index];
|
|||
|
return ListTile(
|
|||
|
leading: SizedBox(
|
|||
|
width: 40,
|
|||
|
child: Image.network(character.imageUrl, width: 50, height: 50),
|
|||
|
),
|
|||
|
title: Text(character.name),
|
|||
|
subtitle: Text(character.typeString),
|
|||
|
trailing: IconButton(
|
|||
|
icon: Icon(
|
|||
|
character.isLiked ? Icons.favorite : Icons.favorite_border,
|
|||
|
color: character.isLiked ? Colors.red : null,
|
|||
|
),
|
|||
|
onPressed: () {
|
|||
|
setState(() {
|
|||
|
character.isLiked = !character.isLiked;
|
|||
|
});
|
|||
|
ScaffoldMessenger.of(context).showSnackBar(
|
|||
|
SnackBar(
|
|||
|
content: Text(
|
|||
|
character.isLiked
|
|||
|
? '${character.name} понравился вам!'
|
|||
|
: '${character.name} убран из лайков.',
|
|||
|
),
|
|||
|
duration: Duration(seconds: 2),
|
|||
|
),
|
|||
|
);
|
|||
|
},
|
|||
|
),
|
|||
|
onTap: () {
|
|||
|
Navigator.push(
|
|||
|
context,
|
|||
|
MaterialPageRoute(
|
|||
|
builder: (context) => CharacterDetailPage(character: character),
|
|||
|
),
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
},
|
|||
|
),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class CharacterSearchDelegate extends SearchDelegate {
|
|||
|
final Function(String) onSearch;
|
|||
|
|
|||
|
CharacterSearchDelegate(this.onSearch);
|
|||
|
|
|||
|
@override
|
|||
|
Widget buildSuggestions(BuildContext context) {
|
|||
|
return ListView();
|
|||
|
}
|
|||
|
|
|||
|
@override
|
|||
|
Widget buildResults(BuildContext context) {
|
|||
|
onSearch(query); // Выполняем поиск
|
|||
|
return FutureBuilder<List<Character>>(
|
|||
|
future: CharacterService().getCharacters(search: query), // Запрашиваем персонажей с фильтром
|
|||
|
builder: (context, snapshot) {
|
|||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
|||
|
return Center(child: CircularProgressIndicator());
|
|||
|
} else if (snapshot.hasError) {
|
|||
|
return Center(child: Text('Ошибка: ${snapshot.error}'));
|
|||
|
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
|||
|
return Center(child: Text('Нет результатов для "$query"'));
|
|||
|
} else {
|
|||
|
final characters = snapshot.data!;
|
|||
|
return ListView.builder(
|
|||
|
itemCount: characters.length,
|
|||
|
itemBuilder: (context, index) {
|
|||
|
final character = characters[index];
|
|||
|
return ListTile(
|
|||
|
title: Text(character.name),
|
|||
|
subtitle: Text(character.typeString),
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
@override
|
|||
|
List<Widget> buildActions(BuildContext context) {
|
|||
|
return [
|
|||
|
IconButton(
|
|||
|
icon: Icon(Icons.clear),
|
|||
|
onPressed: () {
|
|||
|
query = ''; // Очищаем запрос
|
|||
|
},
|
|||
|
),
|
|||
|
];
|
|||
|
}
|
|||
|
|
|||
|
@override
|
|||
|
Widget buildLeading(BuildContext context) {
|
|||
|
return IconButton(
|
|||
|
icon: Icon(Icons.arrow_back),
|
|||
|
onPressed: () {
|
|||
|
close(context, null); // Закрываем поиск
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
}
|