From fbd70f10bda62aed3394a8164bbe02469a92f1fe Mon Sep 17 00:00:00 2001
From: DavidMakarov <wshirotame@gmail.com>
Date: Fri, 4 Oct 2024 20:36:43 +0400
Subject: [PATCH] add snackBar for liked state, details_page

---
 lib/domain/models/card.dart              |   6 ++
 lib/main.dart                            | 120 +----------------------
 lib/views/details_page/details_page.dart |  51 ++++++++++
 lib/views/home_page/card.dart            | 118 ++++++++++++++++++++++
 lib/views/home_page/home_page.dart       |  71 ++++++++++++++
 5 files changed, 248 insertions(+), 118 deletions(-)
 create mode 100644 lib/domain/models/card.dart
 create mode 100644 lib/views/details_page/details_page.dart
 create mode 100644 lib/views/home_page/card.dart
 create mode 100644 lib/views/home_page/home_page.dart

diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart
new file mode 100644
index 0000000..9308ff4
--- /dev/null
+++ b/lib/domain/models/card.dart
@@ -0,0 +1,6 @@
+class CardData {
+  final String textData;
+  final String imageUrl;
+
+  const CardData({required this.textData, required this.imageUrl});
+}
diff --git a/lib/main.dart b/lib/main.dart
index c4b12cf..9adb4a0 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'package:flutter_project/views/home_page/home_page.dart';
 
 void main() {
   runApp(const MyApp());
@@ -15,124 +16,7 @@ class MyApp extends StatelessWidget {
         colorScheme: ColorScheme.fromSeed(seedColor: Colors.lightGreen),
         useMaterial3: true,
       ),
-      home: const MyHomePage(),
-    );
-  }
-}
-
-class MyHomePage extends StatefulWidget {
-  const MyHomePage({super.key});
-
-  @override
-  State<MyHomePage> createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State<MyHomePage> {
-  List<_CardData> data = [
-    _CardData(
-        textData: "250x150 picture",
-        imageUrl: "https://loremflickr.com/250/150/kitty"),
-    _CardData(
-        textData: "200x250 picture",
-        imageUrl: "https://loremflickr.com/200/250/kitty"),
-    _CardData(
-        textData: "200x200 picture",
-        imageUrl: "https://loremflickr.com/200/200/kitty"),
-    _CardData(
-        textData: "100x150 picture",
-        imageUrl: "https://loremflickr.com/100/150/kitty"),
-    _CardData(
-        textData: "300x150 picture",
-        imageUrl: "https://loremflickr.com/350/150/kitty"),
-  ];
-  @override
-  Widget build(BuildContext context) {
-    return Scaffold(
-        appBar: AppBar(
-          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
-          title: Text(
-            'Item list',
-          ),
-        ),
-        body: SingleChildScrollView(
-          child: Column(
-            children: data.map((d) => _Card.withData(d)).toList(),
-          ),
-        ));
-  }
-}
-
-class _CardData {
-  final String textData;
-  final String imageUrl;
-
-  const _CardData({required this.textData, required this.imageUrl});
-}
-
-class _Card extends StatelessWidget {
-  final String text;
-  final String imageUrl;
-
-  const _Card({required this.text, required this.imageUrl});
-
-  factory _Card.withData(_CardData d) => _Card(
-        text: d.textData,
-        imageUrl: d.imageUrl,
-      );
-
-  @override
-  Widget build(BuildContext context) {
-    return Padding(
-      padding: const EdgeInsets.all(8.0),
-      child: Container(
-          margin: EdgeInsets.all(5.0),
-          padding: EdgeInsets.all(8.0),
-          decoration: BoxDecoration(
-              boxShadow: [
-                BoxShadow(
-                    color: Colors.grey.withOpacity(0.5),
-                    spreadRadius: 3,
-                    offset: const Offset(0, 2),
-                    blurRadius: 4)
-              ],
-              color: Theme.of(context).colorScheme.inversePrimary,
-              borderRadius: BorderRadius.circular(20)),
-          child: Row(
-            crossAxisAlignment: CrossAxisAlignment.start,
-            children: [
-              ClipRRect(
-                borderRadius: BorderRadius.circular(20),
-                child: SizedBox(
-                  width: 150,
-                  height: 150,
-                  child: Image.network(
-                    imageUrl == ""
-                        ? "https://loremflickr.com/150/150?random=1"
-                        : imageUrl,
-                    fit: BoxFit.cover,
-                  ),
-                ),
-              ),
-              Expanded(
-                child: Padding(
-                  padding: const EdgeInsets.only(left: 16.0, top: 16.0),
-                  child: Column(
-                    crossAxisAlignment: CrossAxisAlignment.start,
-                    children: [
-                      Text(
-                        text,
-                        style: Theme.of(context).textTheme.headlineSmall,
-                      ),
-                      Text(
-                        "This is card with picture and text",
-                        style: Theme.of(context).textTheme.labelSmall,
-                      ),
-                    ],
-                  ),
-                ),
-              )
-            ],
-          )),
+      home: const HomePage(),
     );
   }
 }
diff --git a/lib/views/details_page/details_page.dart b/lib/views/details_page/details_page.dart
new file mode 100644
index 0000000..9f732d6
--- /dev/null
+++ b/lib/views/details_page/details_page.dart
@@ -0,0 +1,51 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+
+import '../../domain/models/card.dart';
+
+class DetailsPage extends StatelessWidget {
+  final CardData data;
+
+  const DetailsPage(this.data, {super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+      ),
+      body: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          Container(
+            color: Theme.of(context).colorScheme.inversePrimary,
+            child: Center(
+              child: Padding(
+                padding: const EdgeInsets.only(top: 10, bottom: 10),
+                child: ClipRRect(
+                    borderRadius: BorderRadius.all(Radius.circular(20)),
+                    child: Image.network(data.imageUrl == ""
+                        ? "https://loremflickr.com/150/150?random=1"
+                        : data.imageUrl)),
+              ),
+            ),
+          ),
+          Padding(
+            padding: const EdgeInsets.all(10),
+            child: Text(
+              data.textData,
+              style: Theme.of(context).textTheme.headlineLarge,
+            ),
+          ),
+          Padding(
+            padding: const EdgeInsets.all(10),
+            child: Text(
+              "This is card with some picture and provided text",
+              style: Theme.of(context).textTheme.bodyLarge,
+            ),
+          )
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/views/home_page/card.dart b/lib/views/home_page/card.dart
new file mode 100644
index 0000000..cb28fa8
--- /dev/null
+++ b/lib/views/home_page/card.dart
@@ -0,0 +1,118 @@
+part of 'home_page.dart';
+
+typedef onLikeCallback = void Function(String title, bool isLiked)?;
+
+class _Card extends StatefulWidget {
+  final String text;
+  final String imageUrl;
+  final onLikeCallback onLike;
+  final VoidCallback? onTap;
+
+  const _Card(
+      {required this.text, required this.imageUrl, this.onLike, this.onTap});
+
+  factory _Card.withData(CardData d,
+          {onLikeCallback onLike, VoidCallback? onTap}) =>
+      _Card(
+        text: d.textData,
+        imageUrl: d.imageUrl,
+        onLike: onLike,
+        onTap: onTap,
+      );
+
+  @override
+  State<_Card> createState() => _CardState();
+}
+
+class _CardState extends State<_Card> {
+  bool isLiked = false;
+
+  @override
+  Widget build(BuildContext context) {
+    return GestureDetector(
+      onTap: widget.onTap,
+      child: Padding(
+        padding: const EdgeInsets.all(8.0),
+        child: Container(
+            margin: EdgeInsets.only(left: 15, top: 10, right: 15),
+            decoration: BoxDecoration(
+                boxShadow: [
+                  BoxShadow(
+                      color: Colors.grey.withOpacity(0.5),
+                      spreadRadius: 3,
+                      offset: const Offset(0, 2),
+                      blurRadius: 4)
+                ],
+                color: Theme.of(context).colorScheme.inversePrimary,
+                borderRadius: BorderRadius.circular(20)),
+            child: IntrinsicHeight(
+              child: Row(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  ClipRRect(
+                    borderRadius: BorderRadius.only(
+                        topLeft: Radius.circular(20),
+                        bottomLeft: Radius.circular(20)),
+                    child: SizedBox(
+                      width: 150,
+                      height: 150,
+                      child: Image.network(
+                        widget.imageUrl == ""
+                            ? "https://loremflickr.com/150/150?random=1"
+                            : widget.imageUrl,
+                        fit: BoxFit.cover,
+                      ),
+                    ),
+                  ),
+                  Expanded(
+                    child: Padding(
+                      padding: const EdgeInsets.only(left: 16.0, top: 16.0),
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          Text(
+                            widget.text,
+                            style: Theme.of(context).textTheme.headlineSmall,
+                          ),
+                          Text(
+                            "This is card with picture and text",
+                            style: Theme.of(context).textTheme.labelSmall,
+                          ),
+                        ],
+                      ),
+                    ),
+                  ),
+                  Column(
+                    children: [
+                      Padding(
+                        padding: const EdgeInsets.only(top: 16.0, right: 8.0),
+                        child: GestureDetector(
+                          onTap: () {
+                            setState(() {
+                              isLiked = !isLiked;
+                            });
+                            widget.onLike?.call(widget.text, isLiked);
+                          },
+                          child: AnimatedSwitcher(
+                            duration: const Duration(milliseconds: 150),
+                            child: isLiked
+                                ? Icon(
+                                    Icons.favorite,
+                                    key: ValueKey<int>(1),
+                                  )
+                                : Icon(
+                                    Icons.favorite_border,
+                                    key: ValueKey<int>(0),
+                                  ),
+                          ),
+                        ),
+                      )
+                    ],
+                  )
+                ],
+              ),
+            )),
+      ),
+    );
+  }
+}
diff --git a/lib/views/home_page/home_page.dart b/lib/views/home_page/home_page.dart
new file mode 100644
index 0000000..c72e3fc
--- /dev/null
+++ b/lib/views/home_page/home_page.dart
@@ -0,0 +1,71 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_project/domain/models/card.dart';
+import 'package:flutter_project/views/details_page/details_page.dart';
+
+part 'card.dart';
+
+class HomePage extends StatefulWidget {
+  const HomePage({super.key});
+
+  @override
+  State<HomePage> createState() => _HomePageState();
+}
+
+class _HomePageState extends State<HomePage> {
+  List<CardData> data = [
+    CardData(
+        textData: "250x150 picture",
+        imageUrl: "https://loremflickr.com/250/150/cat"),
+    CardData(
+        textData: "200x250 picture",
+        imageUrl: "https://loremflickr.com/200/250/cat"),
+    CardData(
+        textData: "200x200 picture",
+        imageUrl: "https://loremflickr.com/200/200/cat"),
+    CardData(
+        textData: "100x150 picture",
+        imageUrl: "https://loremflickr.com/100/150/cat"),
+    CardData(
+        textData: "300x150 picture",
+        imageUrl: "https://loremflickr.com/350/150/cat"),
+  ];
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+        appBar: AppBar(
+          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+          title: Text(
+            'Item list',
+          ),
+        ),
+        body: SingleChildScrollView(
+          child: Column(
+            children: data
+                .map((d) => _Card.withData(d,
+                    onTap: () => _navToDetails(context, d),
+                    onLike: (String title, bool isLiked) =>
+                        _showSnackBar(context, isLiked, title)))
+                .toList(),
+          ),
+        ));
+  }
+
+  void _showSnackBar(BuildContext context, bool isLiked, String title) {
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
+        content: Text(
+          isLiked ? "You liked $title" : "Like removed from $title",
+          style: Theme.of(context).textTheme.bodyLarge,
+        ),
+        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+        duration: const Duration(milliseconds: 1200),
+      ));
+    });
+  }
+
+  void _navToDetails(BuildContext context, CardData d) {
+    Navigator.push(
+        context, CupertinoPageRoute(builder: (context) => DetailsPage(d)));
+  }
+}