Compare commits
5 Commits
6ff2744c61
...
0a491ca34b
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a491ca34b | |||
| 16d0ddca78 | |||
| f941b26224 | |||
| c6520041a6 | |||
| 7f0cef4b23 |
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
}
|
||||||
BIN
assets/logo.png
Normal file
BIN
assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
assets/product.png
Normal file
BIN
assets/product.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 455 KiB |
54
lib/components/card.dart
Normal file
54
lib/components/card.dart
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ProductCard extends StatelessWidget {
|
||||||
|
final Image imagePath;
|
||||||
|
final String name;
|
||||||
|
final String 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),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
350
lib/main.dart
350
lib/main.dart
@@ -3,13 +3,17 @@ import 'dart:js_interop' as js;
|
|||||||
import 'dart:js_interop_unsafe' as js_util;
|
import 'dart:js_interop_unsafe' as js_util;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gymlink_module_web/components/card.dart';
|
||||||
|
import 'package:gymlink_module_web/pages/basket.dart';
|
||||||
|
import 'package:gymlink_module_web/pages/detail.dart';
|
||||||
|
import 'package:gymlink_module_web/pages/order_history.dart';
|
||||||
|
import 'package:gymlink_module_web/theme.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DemoScreen { counter, textField }
|
|
||||||
|
|
||||||
class MyApp extends StatefulWidget {
|
class MyApp extends StatefulWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
@@ -18,11 +22,47 @@ class MyApp extends StatefulWidget {
|
|||||||
State<MyApp> createState() => _MyAppState();
|
State<MyApp> createState() => _MyAppState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const List<Map<String, String>> testData = [
|
||||||
|
{
|
||||||
|
"name": "Протеин",
|
||||||
|
"image": "product.png",
|
||||||
|
"price": "120",
|
||||||
|
"details": "Test details",
|
||||||
|
"id": "34fa3126-bfaf-5dec-8f4a-b246c097ef73"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Протеин",
|
||||||
|
"image": "product.png",
|
||||||
|
"price": "150",
|
||||||
|
"details": "Test details",
|
||||||
|
"id": "34a26e82-7656-5e98-a44a-c2d01d0b1ad1123"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Протеин",
|
||||||
|
"image": "product.png",
|
||||||
|
"price": "250",
|
||||||
|
"details": "Test details",
|
||||||
|
"id": "4fb204b7-3f9e-52a2-bed1-415c00a31a37123"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Протеин",
|
||||||
|
"image": "product.png",
|
||||||
|
"price": "300",
|
||||||
|
"details": "Test details",
|
||||||
|
"id": "09b2f5bb-683e-5c39-ae89-b8e152fa8bcf123"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Протеин",
|
||||||
|
"image": "product.png",
|
||||||
|
"price": "100",
|
||||||
|
"details": "Test details",
|
||||||
|
"id": "cd1b6817-db94-5394-be1d-af88af79749f123"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
@js.JSExport()
|
@js.JSExport()
|
||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
final _streanController = StreamController<void>.broadcast();
|
final _streamController = StreamController<void>.broadcast();
|
||||||
DemoScreen _currentDemoScreen = DemoScreen.counter;
|
|
||||||
int _counterScreenCount = 0;
|
|
||||||
bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -35,39 +75,17 @@ class _MyAppState extends State<MyApp> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_streanController.close();
|
_streamController.close();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@js.JSExport()
|
|
||||||
void increment() {
|
|
||||||
if (_currentDemoScreen == DemoScreen.counter) {
|
|
||||||
setState(() {
|
|
||||||
_counterScreenCount++;
|
|
||||||
_streanController.add(null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@js.JSExport()
|
|
||||||
void addHandler(void Function() handler) {
|
|
||||||
_streanController.stream.listen((event) {
|
|
||||||
handler();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@js.JSExport()
|
|
||||||
int get count => _counterScreenCount;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Aboba app',
|
title: 'GymLink Module',
|
||||||
theme: ThemeData(
|
theme: myTheme,
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.red),
|
|
||||||
),
|
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
home: demoScreenRouter(_currentDemoScreen),
|
home: MainPage(isLoading: _isLoading),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,148 +97,178 @@ class _MyAppState extends State<MyApp> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget demoScreenRouter(DemoScreen which) {
|
class MainPage extends StatefulWidget {
|
||||||
switch (which) {
|
final bool isLoading;
|
||||||
case DemoScreen.counter:
|
|
||||||
return CounterDemo(
|
const MainPage({
|
||||||
title: 'Counter',
|
super.key,
|
||||||
numToDisplay: _counterScreenCount,
|
required this.isLoading,
|
||||||
incrementHandler: increment,
|
});
|
||||||
isLoading: _isLoading);
|
|
||||||
case DemoScreen.textField:
|
@override
|
||||||
return const TextFieldDemo(title: 'Nasdfs');
|
State<MainPage> createState() => _MainPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MainPageState extends State<MainPage> {
|
||||||
|
Future<void> _goToPage() async {
|
||||||
|
final Uri url = Uri.parse('https://google.com');
|
||||||
|
if (!await launchUrl(url, webOnlyWindowName: '_blank')) {
|
||||||
|
throw 'Could not launch $url';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@js.JSExport()
|
|
||||||
void changeDemoScreenTo(String screenString) {
|
|
||||||
setState(() {
|
|
||||||
switch (screenString) {
|
|
||||||
case 'counter':
|
|
||||||
_currentDemoScreen = DemoScreen.counter;
|
|
||||||
break;
|
|
||||||
case 'textField':
|
|
||||||
_currentDemoScreen = DemoScreen.textField;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CounterDemo extends StatefulWidget {
|
|
||||||
final String title;
|
|
||||||
final int numToDisplay;
|
|
||||||
final VoidCallback incrementHandler;
|
|
||||||
final bool isLoading;
|
|
||||||
|
|
||||||
const CounterDemo(
|
|
||||||
{super.key,
|
|
||||||
required this.title,
|
|
||||||
required this.numToDisplay,
|
|
||||||
required this.incrementHandler,
|
|
||||||
required this.isLoading});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CounterDemo> createState() => _CounterDemoState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CounterDemoState extends State<CounterDemo> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: widget.isLoading
|
appBar: widget.isLoading
|
||||||
? null
|
? null
|
||||||
: AppBar(
|
: AppBar(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
elevation: 0,
|
||||||
title: Row(
|
title: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Padding(
|
||||||
child: TextField(
|
padding: const EdgeInsets.only(right: 8),
|
||||||
decoration: InputDecoration(
|
child: Image.asset('logo.png', width: 24, height: 24),
|
||||||
hintText: 'Search',
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
suffixIcon: const Icon(
|
|
||||||
Icons.search,
|
|
||||||
color: Colors.blue,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
Align(
|
||||||
ElevatedButton(
|
alignment: Alignment.centerRight,
|
||||||
onPressed: () {},
|
child: Text(
|
||||||
style: ElevatedButton.styleFrom(
|
'Powered by GymLink',
|
||||||
padding: const EdgeInsets.all(0),
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
shape: const CircleBorder(
|
|
||||||
side: BorderSide(
|
|
||||||
color: Colors.blue,
|
|
||||||
width: 2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const Icon(
|
|
||||||
Icons.shopping_basket,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 36,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.all(0),
|
|
||||||
shape: const CircleBorder(
|
|
||||||
side: BorderSide(
|
|
||||||
color: Colors.blue,
|
|
||||||
width: 2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const Icon(
|
|
||||||
Icons.history,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 36,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
toolbarHeight: 30,
|
||||||
),
|
),
|
||||||
body: widget.isLoading
|
body: widget.isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: const Center(
|
: Column(
|
||||||
child: Column(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
children: <Widget>[
|
||||||
children: <Widget>[
|
Padding(
|
||||||
Text(
|
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||||
'Здесь будут товары',
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
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: _goToPage,
|
||||||
|
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: () {
|
||||||
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
|
builder: (context) => const BasketPage(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
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: () {
|
||||||
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
|
builder: (context) => const HistoryPage(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
Expanded(
|
||||||
|
child: GridView.builder(
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount:
|
||||||
|
(MediaQuery.sizeOf(context).width ~/ 250).floor(),
|
||||||
|
),
|
||||||
|
itemCount: testData.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final product = testData[index];
|
||||||
|
return ProductCard(
|
||||||
|
imagePath: Image.asset(
|
||||||
|
product['image']!,
|
||||||
|
width: 100,
|
||||||
|
),
|
||||||
|
name: product['name']!,
|
||||||
|
price: product['price']!,
|
||||||
|
onTap: () => Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => DetailPage(
|
||||||
|
name: product['name']!,
|
||||||
|
description: product['details']!,
|
||||||
|
price: product['price']!,
|
||||||
|
id: product['id']!,
|
||||||
|
image: Image.asset(product['image']!, width: 300),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TextFieldDemo extends StatelessWidget {
|
|
||||||
const TextFieldDemo({super.key, required this.title});
|
|
||||||
final String title;
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(title),
|
|
||||||
),
|
|
||||||
body: const Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(14.0),
|
|
||||||
child: TextField(
|
|
||||||
maxLines: null,
|
|
||||||
decoration: InputDecoration(border: OutlineInputBorder()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
21
lib/pages/basket.dart
Normal file
21
lib/pages/basket.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class BasketPage extends StatelessWidget {
|
||||||
|
const BasketPage({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(Icons.arrow_back),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
title: const Text('Корзина'),
|
||||||
|
),
|
||||||
|
body: const Center(
|
||||||
|
child: Text('Корзина'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
94
lib/pages/detail.dart
Normal file
94
lib/pages/detail.dart
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
//TODO: Сделать получение инфы через объект
|
||||||
|
class DetailPage extends StatelessWidget {
|
||||||
|
final String name;
|
||||||
|
final String description;
|
||||||
|
final String price;
|
||||||
|
final String id;
|
||||||
|
final Image image;
|
||||||
|
const DetailPage(
|
||||||
|
{super.key,
|
||||||
|
required this.name,
|
||||||
|
required this.description,
|
||||||
|
required this.price,
|
||||||
|
required this.id,
|
||||||
|
required this.image});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(Icons.arrow_back),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
title: Text('$name - $id'),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: SizedBox(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
height: MediaQuery.sizeOf(context).height,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
image,
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 60, 60, 60),
|
||||||
|
child: SizedBox(
|
||||||
|
width: 340,
|
||||||
|
height: MediaQuery.sizeOf(context).height,
|
||||||
|
child: Card(
|
||||||
|
elevation: 4,
|
||||||
|
color: const Color(0xFFF2F3F9),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(20, 15, 10, 15),
|
||||||
|
child: Text(
|
||||||
|
description,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: const AlignmentDirectional(0, -1),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 60, 0, 0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Стоимость $price',
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => {},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Theme.of(context).primaryColor,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(50),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(
|
||||||
|
34, 10, 34, 10)),
|
||||||
|
child: const Text('Добавить в корзину'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
lib/pages/order_history.dart
Normal file
21
lib/pages/order_history.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class HistoryPage extends StatelessWidget {
|
||||||
|
const HistoryPage({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(Icons.arrow_back),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
title: const Text('История заказов'),
|
||||||
|
),
|
||||||
|
body: const Center(
|
||||||
|
child: Text('История заказов'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
26
lib/theme.dart
Normal file
26
lib/theme.dart
Normal file
@@ -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<int, Color> 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);
|
||||||
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||||
|
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import url_launcher_macos
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: flutter_application_1
|
name: gymlink_module_web
|
||||||
description: "A new Flutter project."
|
description: "GymLink Flutter Web Module."
|
||||||
# The following line prevents the package from being accidentally published to
|
# The following line prevents the package from being accidentally published to
|
||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
@@ -35,6 +35,7 @@ dependencies:
|
|||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.6
|
cupertino_icons: ^1.0.6
|
||||||
|
url_launcher: ^6.2.6
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -57,6 +58,9 @@ flutter:
|
|||||||
# included with your application, so that you can use the icons in
|
# included with your application, so that you can use the icons in
|
||||||
# the material Icons class.
|
# the material Icons class.
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
assets:
|
||||||
|
- assets/logo.png
|
||||||
|
- assets/product.png
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
# assets:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#flutter_target {
|
#flutter_target {
|
||||||
border: 1px solid #aaa;
|
border: 1px solid #aaa;
|
||||||
width: 320px;
|
width: 80vw;
|
||||||
height: 480px;
|
height: 60vh;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
transition: all 150ms ease-in;
|
transition: all 150ms ease-in;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
Reference in New Issue
Block a user