diff --git a/assets/product.png b/assets/product.png new file mode 100644 index 0000000..47993ff Binary files /dev/null and b/assets/product.png differ diff --git a/lib/components/card.dart b/lib/components/card.dart new file mode 100644 index 0000000..632a76c --- /dev/null +++ b/lib/components/card.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; + +class ProductCard extends StatelessWidget { + final Image imagePath; + final String name; + final int price; + final VoidCallback onTap; + + const ProductCard({ + super.key, + required this.imagePath, + required this.name, + required this.price, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: ConstrainedBox( + constraints: const BoxConstraints(minHeight: 200), + child: Card( + elevation: 3, + color: const Color(0xFFF2F3F9), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + imagePath, + const SizedBox(height: 16), + Text(name, style: Theme.of(context).textTheme.titleLarge), + const SizedBox(height: 8), + Text('\$$price', style: Theme.of(context).textTheme.titleSmall), + ], + ), + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: [ + // imagePath, + // const SizedBox(height: 16), + // Text(name, style: Theme.of(context).textTheme.titleLarge), + // const SizedBox(height: 8), + // Text('\$$price', style: Theme.of(context).textTheme.titleSmall), + // ], + // ), + ), + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index 075177a..06fe723 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,8 @@ import 'dart:js_interop' as js; import 'dart:js_interop_unsafe' as js_util; import 'package:flutter/material.dart'; +import 'package:flutter_application_1/components/card.dart'; +import 'package:flutter_application_1/theme.dart'; void main() { runApp(const MyApp()); @@ -42,9 +44,7 @@ class _MyAppState extends State { Widget build(BuildContext context) { return MaterialApp( title: 'GymLink Module', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), - ), + theme: myTheme, debugShowCheckedModeBanner: false, home: gymLinkScreenRouter(_currentGymLinkScreen), ); @@ -110,120 +110,145 @@ class _MainPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: widget.isLoading - ? null - : AppBar( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + appBar: widget.isLoading + ? null + : AppBar( + backgroundColor: Colors.white, + elevation: 0, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(right: 8), + child: Image.asset('logo.png', width: 24, height: 24), + ), + Align( + alignment: Alignment.centerRight, + child: Text( + 'Powered by GymLink', + style: Theme.of(context).textTheme.titleSmall, + ), + ), + ], + ), + toolbarHeight: 30, + ), + body: widget.isLoading + ? const Center(child: CircularProgressIndicator()) + : Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: Image.asset('logo.png', width: 24, height: 24), - ), - Align( - alignment: Alignment.centerRight, - child: Text('Powered by GymLink', - style: Theme.of(context).textTheme.titleSmall), - ), - ])), - body: widget.isLoading - ? const Center(child: CircularProgressIndicator()) - : Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: TextField( - decoration: InputDecoration( - hintText: 'Search', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - ), - suffixIcon: Padding( - padding: const EdgeInsets.only(right: 8), - child: ElevatedButton( - onPressed: () { - debugPrint('search button pressed'); - }, - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric( - vertical: 8, horizontal: 0), - minimumSize: const Size( - 50, kMinInteractiveDimension), - backgroundColor: Colors.blue, - shape: const CircleBorder(), - ), - child: const Icon( - Icons.search, - color: Colors.white, - size: 24, - ), + Expanded( + child: TextField( + decoration: InputDecoration( + hintText: 'Search', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + suffixIcon: Padding( + padding: const EdgeInsets.only(right: 8), + child: ElevatedButton( + onPressed: () { + debugPrint('search button pressed'); + }, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric( + vertical: 8, horizontal: 0), + minimumSize: + const Size(50, kMinInteractiveDimension), + backgroundColor: + Theme.of(context).primaryColor, + shape: const CircleBorder(), + ), + child: const Icon( + Icons.search, + color: Colors.white, + size: 24, ), ), ), ), ), - const SizedBox(width: 8), - ElevatedButton( - onPressed: () { - setState(() { - widget.changeGymLinkScreenTo('basket'); - }); - }, - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.all(0), - backgroundColor: Colors.blue, - shape: const CircleBorder( - side: BorderSide( - color: Colors.black, - width: 1, - ), + ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: () { + setState(() { + widget.changeGymLinkScreenTo('basket'); + }); + }, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.all(0), + minimumSize: const Size(40, kMinInteractiveDimension), + backgroundColor: Theme.of(context).primaryColor, + shape: const CircleBorder( + side: BorderSide( + color: Colors.black, + width: 1, ), ), - child: const Icon( - Icons.shopping_basket, - color: Colors.white, - size: 24, - ), ), - const SizedBox(width: 8), - ElevatedButton( - onPressed: () { - setState(() { - widget.changeGymLinkScreenTo('history'); - }); - }, - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.all(0), - backgroundColor: Colors.blue, - shape: const CircleBorder( - side: BorderSide( - color: Colors.black, - width: 1, - ), + child: const Icon( + Icons.shopping_basket, + color: Colors.white, + size: 24, + ), + ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: () { + setState(() { + widget.changeGymLinkScreenTo('history'); + }); + }, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.all(0), + minimumSize: const Size(40, kMinInteractiveDimension), + backgroundColor: Theme.of(context).primaryColor, + shape: const CircleBorder( + side: BorderSide( + color: Colors.black, + width: 1, ), ), - child: const Icon( - Icons.history, - color: Colors.white, - size: 24, - ), ), - ], + child: const Icon( + Icons.history, + color: Colors.white, + size: 24, + ), + ), + ], + ), + ), + Expanded( + child: GridView.builder( + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, ), - ]) - // : const Center( - // child: Column( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Text( - // 'Здесь будут товары', - // ), - // ], - // ), - // ), - ); + itemCount: 10, + itemBuilder: (context, index) { + return ProductCard( + imagePath: Image.asset( + 'product.png', + width: 100, + ), + name: 'Product $index', + price: 100, + onTap: () => debugPrint('product $index pressed'), + ); + }, + ), + ), + ], + ), + ); } } diff --git a/lib/theme.dart b/lib/theme.dart new file mode 100644 index 0000000..6726ddc --- /dev/null +++ b/lib/theme.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +final ThemeData myTheme = ThemeData( + colorScheme: ColorScheme.fromSeed( + seedColor: getMaterialColor(const Color(0x007d85ff)))); + +MaterialColor getMaterialColor(Color color) { + final int red = color.red; + final int green = color.green; + final int blue = color.blue; + + final Map shades = { + 50: Color.fromRGBO(red, green, blue, .1), + 100: Color.fromRGBO(red, green, blue, .2), + 200: Color.fromRGBO(red, green, blue, .3), + 300: Color.fromRGBO(red, green, blue, .4), + 400: Color.fromRGBO(red, green, blue, .5), + 500: Color.fromRGBO(red, green, blue, .6), + 600: Color.fromRGBO(red, green, blue, .7), + 700: Color.fromRGBO(red, green, blue, .8), + 800: Color.fromRGBO(red, green, blue, .9), + 900: Color.fromRGBO(red, green, blue, 1), + }; + + return MaterialColor(color.value, shades); +} diff --git a/pubspec.yaml b/pubspec.yaml index a60d351..5f65fc0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,7 @@ flutter: uses-material-design: true assets: - assets/logo.png + - assets/product.png # To add assets to your application, add an assets section, like this: # assets: