Advertisement
ZergRushA

zadanie flutter

Oct 19th, 2024 (edited)
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.78 KB | None | 0 0
  1. import 'package:flutter/material.dart';
  2. import 'package:shared_preferences/shared_preferences.dart';
  3. import 'package:http/http.dart' as http;
  4. import 'dart:convert';
  5.  
  6. void main() => runApp(CakeApp());
  7.  
  8. class CakeApp extends StatelessWidget {
  9. @override
  10. Widget build(BuildContext context) {
  11. return MaterialApp(
  12. title: 'Cake List',
  13. home: CakeListScreen(),
  14. );
  15. }
  16. }
  17.  
  18. class CakeListScreen extends StatefulWidget {
  19. @override
  20. _CakeListScreenState createState() => _CakeListScreenState();
  21. }
  22.  
  23. class _CakeListScreenState extends State<CakeListScreen> {
  24. List<Cake> cakes = [];
  25. List<Cake> favoriteCakes = [];
  26. bool showFavorites = false;
  27.  
  28. @override
  29. void initState() {
  30. super.initState();
  31. fetchCakes();
  32. loadFavorites();
  33. }
  34.  
  35.  
  36. void updateCake(Cake updatedCake) {
  37. setState(() {
  38. final index = cakes.indexWhere((cake) => cake.rowId == updatedCake.rowId);
  39. if (index != -1) {
  40. cakes[index] = updatedCake;
  41. }
  42. // Если обновленный торт в избранных, обновляем его
  43. if (favoriteCakes.contains(updatedCake)) {
  44. final favIndex = favoriteCakes.indexWhere((cake) => cake.rowId == updatedCake.rowId);
  45. if (favIndex != -1) {
  46. favoriteCakes[favIndex] = updatedCake;
  47. }
  48. }
  49. });
  50. }
  51.  
  52. Future<void> fetchCakes() async {
  53. final uriString = "https://v1.slashapi.com/mirea/google-sheets/NdF76f0ELv/list1";
  54. final response = await http.get(Uri.parse(uriString));
  55. final jsonResponse = jsonDecode(response.body) as Map<String, dynamic>;
  56. setState(() {
  57. cakes = (jsonResponse['data'] as List)
  58. .map((cake) => Cake.fromJson(cake))
  59. .toList();
  60. });
  61. }
  62.  
  63. Future<void> loadFavorites() async {
  64. final prefs = await SharedPreferences.getInstance();
  65. final favoriteIds = prefs.getStringList('favorites') ?? [];
  66. setState(() {
  67. favoriteCakes =
  68. cakes.where((cake) => favoriteIds.contains('${cake.rowId}')).toList();
  69. });
  70. }
  71.  
  72. Future<void> toggleFavorite(Cake cake) async {
  73. final prefs = await SharedPreferences.getInstance();
  74. final favoriteIds = prefs.getStringList('favorites') ?? [];
  75. if (favoriteIds.contains('${cake.rowId}')) {
  76. favoriteIds.remove('${cake.rowId}');
  77. } else {
  78. favoriteIds.add('${cake.rowId}');
  79. }
  80. await prefs.setStringList('favorites', favoriteIds);
  81. loadFavorites();
  82. }
  83.  
  84. void addNewCake(Cake cake) {
  85. setState(() {
  86. cakes.add(cake);
  87. });
  88. }
  89.  
  90. @override
  91. Widget build(BuildContext context) {
  92. final displayedCakes = showFavorites ? favoriteCakes : cakes;
  93.  
  94. return Scaffold(
  95. appBar: AppBar(
  96. title: Text('Cake List'),
  97. actions: [
  98. IconButton(
  99. icon: Icon(showFavorites ? Icons.favorite : Icons.favorite_border),
  100. onPressed: () {
  101. setState(() {
  102. showFavorites = !showFavorites;
  103. });
  104. },
  105. ),
  106. IconButton(
  107. icon: Icon(Icons.add),
  108. onPressed: () {
  109. Navigator.push(
  110. context,
  111. MaterialPageRoute(
  112. builder: (context) => AddCakeScreen(onAddCake: addNewCake),
  113. ),
  114. );
  115. },
  116. ),
  117. ],
  118. ),
  119. body: ListView.builder(
  120. itemCount: displayedCakes.length,
  121. itemBuilder: (context, index) {
  122. final cake = displayedCakes[index];
  123. return Card(
  124. child: ListTile(
  125. title: Text(cake.name),
  126. subtitle: Text(cake.description),
  127. trailing: IconButton(
  128. icon: Icon(favoriteCakes.contains(cake)
  129. ? Icons.favorite
  130. : Icons.favorite_border),
  131. onPressed: () => toggleFavorite(cake),
  132. ),
  133. onTap: () {
  134. Navigator.push(
  135. context,
  136. MaterialPageRoute(
  137. builder: (context) => CakeDetailScreen(cake: cake, onUpdateCake: updateCake),
  138. ),
  139. );
  140. },
  141. ),
  142. );
  143. },
  144. ),
  145. );
  146. }
  147. }
  148.  
  149. class CakeDetailScreen extends StatelessWidget {
  150. final Cake cake;
  151. final Function(Cake) onUpdateCake;
  152.  
  153. CakeDetailScreen({required this.cake, required this.onUpdateCake});
  154.  
  155. @override
  156. Widget build(BuildContext context) {
  157. return Scaffold(
  158. appBar: AppBar(
  159. title: Text(cake.name),
  160. ),
  161. body: Padding(
  162. padding: const EdgeInsets.all(16.0),
  163. child: Column(
  164. crossAxisAlignment: CrossAxisAlignment.start,
  165. children: [
  166. Text('Description: ${cake.description}', style: TextStyle(fontSize: 16)),
  167. SizedBox(height: 8),
  168. Text('Category: ${cake.category}', style: TextStyle(fontSize: 16)),
  169. SizedBox(height: 8),
  170. Text('Size: ${cake.size}', style: TextStyle(fontSize: 16)),
  171. SizedBox(height: 16),
  172. ElevatedButton(
  173. onPressed: () {
  174. Navigator.push(
  175. context,
  176. MaterialPageRoute(
  177. builder: (context) => EditCakeScreen(
  178. cake: cake,
  179. onUpdateCake: onUpdateCake,
  180. ),
  181. ),
  182. );
  183. },
  184. child: Text('Edit Cake'),
  185. ),
  186. ],
  187. ),
  188. ),
  189. );
  190. }
  191. }
  192.  
  193. class EditCakeScreen extends StatefulWidget {
  194. final Cake cake;
  195. final Function(Cake) onUpdateCake;
  196.  
  197. EditCakeScreen({required this.cake, required this.onUpdateCake});
  198.  
  199. @override
  200. _EditCakeScreenState createState() => _EditCakeScreenState();
  201. }
  202.  
  203. class _EditCakeScreenState extends State<EditCakeScreen> {
  204. final _formKey = GlobalKey<FormState>();
  205. late TextEditingController _nameController;
  206. late TextEditingController _descriptionController;
  207. late TextEditingController _categoryController;
  208. late TextEditingController _sizeController;
  209.  
  210. @override
  211. void initState() {
  212. super.initState();
  213. _nameController = TextEditingController(text: widget.cake.name);
  214. _descriptionController = TextEditingController(text: widget.cake.description);
  215. _categoryController = TextEditingController(text: widget.cake.category);
  216. _sizeController = TextEditingController(text: widget.cake.size);
  217. }
  218.  
  219. @override
  220. void dispose() {
  221. _nameController.dispose();
  222. _descriptionController.dispose();
  223. _categoryController.dispose();
  224. _sizeController.dispose();
  225. super.dispose();
  226. }
  227.  
  228. @override
  229. Widget build(BuildContext context) {
  230. return Scaffold(
  231. appBar: AppBar(
  232. title: Text('Edit Cake'),
  233. ),
  234. body: Padding(
  235. padding: const EdgeInsets.all(16.0),
  236. child: Form(
  237. key: _formKey,
  238. child: Column(
  239. children: [
  240. TextFormField(
  241. controller: _nameController,
  242. decoration: InputDecoration(labelText: 'Name'),
  243. validator: (value) =>
  244. value == null || value.isEmpty ? 'Enter a name' : null,
  245. ),
  246. TextFormField(
  247. controller: _descriptionController,
  248. decoration: InputDecoration(labelText: 'Description'),
  249. validator: (value) =>
  250. value == null || value.isEmpty ? 'Enter a description' : null,
  251. ),
  252. TextFormField(
  253. controller: _categoryController,
  254. decoration: InputDecoration(labelText: 'Category'),
  255. ),
  256. TextFormField(
  257. controller: _sizeController,
  258. decoration: InputDecoration(labelText: 'Size'),
  259. ),
  260. SizedBox(height: 20),
  261. ElevatedButton(
  262. onPressed: () {
  263. if (_formKey.currentState?.validate() == true) {
  264. final updatedCake = Cake(
  265. name: _nameController.text,
  266. description: _descriptionController.text,
  267. category: _categoryController.text,
  268. size: _sizeController.text,
  269. rowId: widget.cake.rowId,
  270. );
  271. widget.onUpdateCake(updatedCake);
  272. Navigator.pop(context);
  273. }
  274. },
  275. child: Text('Save Changes'),
  276. ),
  277. ],
  278. ),
  279. ),
  280. ),
  281. );
  282. }
  283. }
  284.  
  285.  
  286.  
  287. class AddCakeScreen extends StatefulWidget {
  288. final Function(Cake) onAddCake;
  289.  
  290. AddCakeScreen({required this.onAddCake});
  291.  
  292. @override
  293. _AddCakeScreenState createState() => _AddCakeScreenState();
  294. }
  295.  
  296. class _AddCakeScreenState extends State<AddCakeScreen> {
  297. final _formKey = GlobalKey<FormState>();
  298. final _nameController = TextEditingController();
  299. final _descriptionController = TextEditingController();
  300. final _categoryController = TextEditingController();
  301. final _sizeController = TextEditingController();
  302.  
  303. @override
  304. Widget build(BuildContext context) {
  305. return Scaffold(
  306. appBar: AppBar(
  307. title: Text('Add New Cake'),
  308. ),
  309. body: Padding(
  310. padding: const EdgeInsets.all(16.0),
  311. child: Form(
  312. key: _formKey,
  313. child: Column(
  314. children: [
  315. TextFormField(
  316. controller: _nameController,
  317. decoration: InputDecoration(labelText: 'Name'),
  318. validator: (value) =>
  319. value == null || value.isEmpty ? 'Enter a name' : null,
  320. ),
  321. TextFormField(
  322. controller: _descriptionController,
  323. decoration: InputDecoration(labelText: 'Description'),
  324. validator: (value) =>
  325. value == null || value.isEmpty ? 'Enter a description' : null,
  326. ),
  327. TextFormField(
  328. controller: _categoryController,
  329. decoration: InputDecoration(labelText: 'Category'),
  330. ),
  331. TextFormField(
  332. controller: _sizeController,
  333. decoration: InputDecoration(labelText: 'Size'),
  334. ),
  335. SizedBox(height: 20),
  336. ElevatedButton(
  337. onPressed: () {
  338. if (_formKey.currentState?.validate() == true) {
  339. final newCake = Cake(
  340. name: _nameController.text,
  341. description: _descriptionController.text,
  342. category: _categoryController.text,
  343. size: _sizeController.text,
  344. rowId: DateTime.now().millisecondsSinceEpoch,
  345. );
  346. widget.onAddCake(newCake);
  347. Navigator.pop(context);
  348. }
  349. },
  350. child: Text('Add Cake'),
  351. ),
  352. ],
  353. ),
  354. ),
  355. ),
  356. );
  357. }
  358. }
  359.  
  360. class Cake {
  361. final String name;
  362. final String description;
  363. final String category;
  364. final String size;
  365. final int rowId;
  366.  
  367. Cake({
  368. required this.name,
  369. required this.description,
  370. required this.category,
  371. required this.size,
  372. required this.rowId,
  373. });
  374.  
  375. factory Cake.fromJson(Map<String, dynamic> json) {
  376. return Cake(
  377. name: json['name'],
  378. description: json['description'],
  379. category: json['category'],
  380. size: json['size'],
  381. rowId: json['row_id'],
  382. );
  383. }
  384.  
  385. Map<String, dynamic> toJson() {
  386. return {
  387. 'name': name,
  388. 'description': description,
  389. 'category': category,
  390. 'size': size,
  391. 'row_id': rowId,
  392. };
  393. }
  394. }
  395.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement