diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart new file mode 100644 index 0000000..6361c41 --- /dev/null +++ b/lib/domain/models/card.dart @@ -0,0 +1,9 @@ +class CardData { + final String text; + final String? imageUrl; + + CardData( + this.text, { + this.imageUrl, + }); +} diff --git a/lib/main.dart b/lib/main.dart index 67c669d..db572bf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:laba1/presentation/home_page/home_page.dart'; void main() { runApp(const MyApp()); @@ -14,131 +15,7 @@ class MyApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.amber, ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), - ); - } -} - -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("Кувшинов Тимур Александрович"), - ), - backgroundColor: Colors.yellow, - body: const MyWidget()); - } -} - -class MyWidget extends StatelessWidget { - const MyWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final List<_CardData> data = [ - _CardData('orange', imageUrl: 'https://kuban24.tv/wp-content/uploads/2023/10/photo_2023-10-02_16-08-02.jpg'), - _CardData("aboba", imageUrl: 'https://masterpiecer-images.s3.yandex.net/5fa453a2d4c51a7:upscaled'), - _CardData("Hello world!!!", imageUrl: 'https://m.media-amazon.com/images/I/81YqUbAZ0GL._AC_UF1000,1000_QL80_.jpg'), - _CardData('(=^・^=)', - imageUrl: - 'https://i.pinimg.com/236x/c8/cc/24/c8cc24bba37a25c009647b8875aae0e3.jpg'), - _CardData('плохо быть старым ' + 'трезвым и больным, ' * 5, - imageUrl: 'https://images.genius.com/c754c6f1755acee741881d55985a6c34.865x865x1.jpg' - ), - ]; - - return Center( - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: data.map((e) => _Card.fromData(e)).toList(), - ), - ), - ); - } -} - -class _CardData { - final String text; - final String? imageUrl; - - _CardData( - this.text, { - this.imageUrl, - }); -} - -class _Card extends StatelessWidget { - final String _text; - final String? imageUrl; - - const _Card(this._text, {Key? key, this.imageUrl}) : super(key: key); - - factory _Card.fromData(_CardData data) => _Card( - data.text, - imageUrl: data.imageUrl, - ); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(10), - margin: const EdgeInsets.all(10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: Colors.amber, - border: Border.all(color: Colors.amberAccent, width: 2), - boxShadow: [BoxShadow( - color: Colors.grey.withOpacity(.5), - blurRadius: 8, - offset: const Offset(0, 5), - spreadRadius: 4, - )] - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ClipRRect( - borderRadius: const BorderRadius.horizontal(left: Radius.circular(150), right: Radius.circular(30)), - child: SizedBox( - height: 160, - width: 90, - child: Image.network( - imageUrl ?? '', - fit: BoxFit.cover, - errorBuilder: (_, __, ___) => const Placeholder(), - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - _text, - style: Theme.of(context).textTheme.headlineLarge, - ), - ), - ), - ], - ), + home: const MyHomePage(title: 'Кувшинов Тимур Александрович'), ); } } diff --git a/lib/presentation/details_page/details_page.dart b/lib/presentation/details_page/details_page.dart new file mode 100644 index 0000000..a1e3eca --- /dev/null +++ b/lib/presentation/details_page/details_page.dart @@ -0,0 +1,61 @@ +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( + backgroundColor: Colors.amber, + appBar: AppBar( + title: const Text("окно с детальной информацией"), + ), + body: SingleChildScrollView( + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(left: 20, top: 20, right: 20), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: Image.network( + data.imageUrl ?? '', + errorBuilder: (_, __, ___) => const Placeholder(), + ), + ), + ), + Container( + margin: const EdgeInsets.all(20), + width: double.infinity, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: const Color.fromARGB(255, 250, 235, 159), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(.5), + blurRadius: 8, + offset: const Offset(0, 5), + spreadRadius: 4, + ) + ]), + child: Center( + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + data.text, + style: Theme.of(context).textTheme.headlineLarge, + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart new file mode 100644 index 0000000..3a0e50b --- /dev/null +++ b/lib/presentation/home_page/card.dart @@ -0,0 +1,108 @@ +part of 'home_page.dart'; + +typedef OnLikeCallback = void Function(bool isLiked)?; + +class _Card extends StatefulWidget { + final String _text; + final String? imageUrl; + final OnLikeCallback onLike; + final VoidCallback? onTap; + + const _Card(this._text, {Key? key, this.imageUrl, this.onLike, this.onTap}) + : super(key: key); + + factory _Card.fromData( + CardData data, { + OnLikeCallback onLike, + VoidCallback? onTap, + }) => + _Card( + data.text, + imageUrl: data.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: Container( + margin: const EdgeInsets.all(10), + constraints: const BoxConstraints(minHeight: 140, maxHeight: 212), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Colors.amber, + border: Border.all(color: Colors.amberAccent, width: 2), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(.5), + blurRadius: 8, + offset: const Offset(0, 5), + spreadRadius: 4, + ) + ]), + child: IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: + const BorderRadius.horizontal(left: Radius.circular(20)), + child: SizedBox( + height: double.infinity, + width: 120, + child: Image.network( + widget.imageUrl ?? '', + fit: BoxFit.cover, + errorBuilder: (_, __, ___) => const Placeholder(), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 8.0, bottom: 8), + child: Text( + widget._text, + style: Theme.of(context).textTheme.headlineMedium, + overflow: TextOverflow.ellipsis, + maxLines: 4, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: GestureDetector( + onTap: () { + isLiked = !isLiked; + setState(() {}); + widget.onLike?.call(isLiked); + }, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 100), + child: isLiked + ? const Icon( + Icons.favorite, + key: ValueKey(0), + ) + : const Icon( + Icons.favorite_border, + key: ValueKey(1), + ), + ), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart new file mode 100644 index 0000000..be859a9 --- /dev/null +++ b/lib/presentation/home_page/home_page.dart @@ -0,0 +1,85 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:laba1/presentation/details_page/details_page.dart'; + +import '../../domain/models/card.dart'; + +part 'card.dart'; + +class MyHomePage extends StatelessWidget { + const MyHomePage({super.key, required this.title}); + + final String title; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + backgroundColor: Colors.yellow, + body: const Body()); + } +} + +class Body extends StatelessWidget { + const Body({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final List data = [ + CardData('orange', + imageUrl: + 'https://kuban24.tv/wp-content/uploads/2023/10/photo_2023-10-02_16-08-02.jpg'), + CardData("aboba", + imageUrl: + 'https://masterpiecer-images.s3.yandex.net/5fa453a2d4c51a7:upscaled'), + CardData("Hello world!!!", + imageUrl: + 'https://m.media-amazon.com/images/I/81YqUbAZ0GL._AC_UF1000,1000_QL80_.jpg'), + CardData('(=^・^=)', + imageUrl: + 'https://i.pinimg.com/236x/c8/cc/24/c8cc24bba37a25c009647b8875aae0e3.jpg'), + CardData('плохо быть старым ' + 'трезвым и больным, ' * 5, + imageUrl: + 'https://images.genius.com/c754c6f1755acee741881d55985a6c34.865x865x1.jpg'), + ]; + + return Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: data + .map((e) => _Card.fromData( + e, + onLike: (bool isLiked) { + _showSnackBar(context, isLiked); + }, + onTap: () => _navToDetails(context, e), + )) + .toList(), + ), + ), + ); + } + + void _navToDetails(BuildContext context, CardData data) { + Navigator.push( + context, + CupertinoPageRoute(builder: (context) => DetailsPage(data)), + ); + } + + void _showSnackBar(BuildContext context, bool isLiked) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + 'Card ${isLiked ? 'liked' : 'unliked'}', + style: Theme.of(context).textTheme.bodyLarge, + ), + backgroundColor: Colors.orangeAccent, + duration: const Duration(seconds: 1), + )); + }); + } +}