From 9e3be50899400a6a983a74f42bdde602301c794d Mon Sep 17 00:00:00 2001 From: Oleg Shabunov Date: Thu, 3 Oct 2024 01:00:26 +0400 Subject: [PATCH] implemented details page --- lib/domain/models/card.dart | 15 ++ .../details_page/details_page.dart | 29 +++ lib/presentation/home_page/card.dart | 167 +++++++++--------- lib/presentation/home_page/home_page.dart | 21 ++- 4 files changed, 141 insertions(+), 91 deletions(-) create mode 100644 lib/domain/models/card.dart create mode 100644 lib/presentation/details_page/details_page.dart diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart new file mode 100644 index 0000000..1132fd0 --- /dev/null +++ b/lib/domain/models/card.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class CardData { + final String title; + final String description; + final IconData icon; + final String? imageUrl; + + CardData({ + required this.title, + required this.description, + this.icon = Icons.adb, + this.imageUrl, + }); +} diff --git a/lib/presentation/details_page/details_page.dart b/lib/presentation/details_page/details_page.dart new file mode 100644 index 0000000..67d35bf --- /dev/null +++ b/lib/presentation/details_page/details_page.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_android_app/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(), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Image.network(data.imageUrl ?? ''), + ), + Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Text(data.title, style: Theme.of(context).textTheme.headlineLarge), + ), + Text(data.description, style: Theme.of(context).textTheme.bodyLarge), + ], + ), + ); + } +} diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart index b8b9c63..5edb47d 100644 --- a/lib/presentation/home_page/card.dart +++ b/lib/presentation/home_page/card.dart @@ -1,19 +1,5 @@ part of 'home_page.dart'; -class _CardData { - final String title; - final String description; - final IconData icon; - final String? imageUrl; - - _CardData({ - required this.title, - required this.description, - this.icon = Icons.adb, - this.imageUrl, - }); -} - typedef OnLikeCallback = void Function(String title, bool isLiked)?; class _Card extends StatefulWidget { @@ -22,6 +8,7 @@ class _Card extends StatefulWidget { final IconData icon; final String? imageUrl; final OnLikeCallback onLike; + final VoidCallback? onTap; const _Card({ super.key, @@ -30,17 +17,20 @@ class _Card extends StatefulWidget { this.icon = Icons.hail, this.imageUrl, this.onLike, + this.onTap, }); factory _Card.fromData( - _CardData data, { + CardData data, { final OnLikeCallback onLike, + VoidCallback? onTap, }) => _Card( title: data.title, description: data.description, icon: data.icon, imageUrl: data.imageUrl, onLike: onLike, + onTap: onTap, ); @override @@ -52,86 +42,89 @@ class _CardState extends State<_Card> { @override Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.fromLTRB(20, 8, 20, 8), - constraints: const BoxConstraints(minHeight: 140), - decoration: BoxDecoration( - color: Colors.deepPurple.shade200, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 4, - offset: const Offset(0, 5), - blurRadius: 6, - ) - ], - ), - child: IntrinsicHeight( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - ClipRRect( - borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(15), - topLeft: Radius.circular(15), - ), - child: SizedBox( - height: double.infinity, - width: 100, - child: Image.network( - widget.imageUrl ?? '', - fit: BoxFit.cover, - errorBuilder: (_, __, ___) => const Placeholder(), + return GestureDetector( + onTap: widget.onTap, + child: Container( + margin: const EdgeInsets.fromLTRB(20, 8, 20, 8), + constraints: const BoxConstraints(minHeight: 140), + decoration: BoxDecoration( + color: Colors.deepPurple.shade200, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 4, + offset: const Offset(0, 5), + blurRadius: 6, + ) + ], + ), + child: IntrinsicHeight( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + ClipRRect( + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(15), + topLeft: Radius.circular(15), + ), + child: SizedBox( + height: double.infinity, + width: 100, + child: Image.network( + widget.imageUrl ?? '', + fit: BoxFit.cover, + errorBuilder: (_, __, ___) => const Placeholder(), + ), ), ), - ), - Flexible( - child: Padding( - padding: const EdgeInsets.only(left: 12.0, top: 12, bottom: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.title, - style: Theme.of(context).textTheme.headlineLarge, - ), - Text( - widget.description, - style: Theme.of(context).textTheme.bodyLarge), - ], + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 12.0, top: 12, bottom: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.title, + style: Theme.of(context).textTheme.headlineLarge, + ), + Text( + widget.description, + style: Theme.of(context).textTheme.bodyLarge), + ], + ), ), ), - ), - Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 16, 16), - child: GestureDetector( - onTap: () { - setState(() { - isLiked = !isLiked; - }); - widget.onLike?.call(widget.title, isLiked); - }, - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 100), - child: isLiked - ? const Icon( - Icons.favorite, - color: Colors.redAccent, - key: ValueKey(0), - ) - : const Icon( - Icons.favorite_border, - key: ValueKey(1), + Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 16, 16), + child: GestureDetector( + onTap: () { + setState(() { + isLiked = !isLiked; + }); + widget.onLike?.call(widget.title, isLiked); + }, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 100), + child: isLiked + ? const Icon( + Icons.favorite, + color: Colors.redAccent, + 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 index 2779709..fde160e 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -1,4 +1,7 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_android_app/domain/models/card.dart'; +import 'package:flutter_android_app/presentation/details_page/details_page.dart'; part 'card.dart'; @@ -42,18 +45,18 @@ class Body extends StatelessWidget { @override Widget build(BuildContext context) { final cardsData = [ - _CardData( + CardData( title: 'Title 1', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', imageUrl: 'https://i.imgur.com/a9WA68S.png', ), - _CardData( + CardData( title: 'Title 2', description: 'Lorem ipsum dolor sit amet', icon: Icons.add_chart_outlined, imageUrl: 'https://i.imgur.com/dAUcs6I.png', ), - _CardData( + CardData( title: 'Title 3', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', imageUrl: 'https://i.imgur.com/m2FhVAK.png', @@ -64,7 +67,13 @@ class Body extends StatelessWidget { child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: cardsData.map((e) => _Card.fromData(e, onLike: (title, isLiked) => _showSnackBar(context, title, isLiked))).toList(), + children: cardsData.map((data) { + return _Card.fromData( + data, + onLike: (String title, bool isLiked) => _showSnackBar(context, title, isLiked), + onTap: () => _navToDetails(context, data), + ); + }).toList(), ), ), ); @@ -82,4 +91,8 @@ class Body extends StatelessWidget { )); }); } + + void _navToDetails(BuildContext context, CardData data) { + Navigator.push(context, CupertinoPageRoute(builder: (context) => DetailsPage(data))); + } }