Compare commits
12 Commits
master
...
e4628e977f
| Author | SHA1 | Date | |
|---|---|---|---|
| e4628e977f | |||
| 4bbe7fbc0b | |||
| 5c3da0964a | |||
| 26f822e83a | |||
| 8805b2a9a0 | |||
| ff29598ec5 | |||
| 727c04d368 | |||
| 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 |
36
lib/components/app_bar.dart
Normal file
36
lib/components/app_bar.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class GymLinkAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
const GymLinkAppBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
shadowColor: null,
|
||||
automaticallyImplyLeading: false,
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 4,
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(30);
|
||||
}
|
||||
71
lib/components/basket_item_card.dart
Normal file
71
lib/components/basket_item_card.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BasketItemCard extends StatelessWidget {
|
||||
final String name;
|
||||
final String price;
|
||||
final String id;
|
||||
final Image image;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const BasketItemCard({
|
||||
super.key,
|
||||
required this.name,
|
||||
required this.price,
|
||||
required this.id,
|
||||
required this.image,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsetsDirectional.symmetric(horizontal: 10, vertical: 10),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
minHeight: 100,
|
||||
maxHeight: 200,
|
||||
minWidth: 400,
|
||||
maxWidth: 600,
|
||||
),
|
||||
child: Card(
|
||||
elevation: 4,
|
||||
color: const Color(0xFFF2F3F9),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
image,
|
||||
const SizedBox(width: 20),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
name,
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
Text('\$$price'),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
onPressed: onTap,
|
||||
icon: const Icon(Icons.close),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
26
lib/components/heading.dart
Normal file
26
lib/components/heading.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class GymLinkHeader extends StatelessWidget {
|
||||
final String title;
|
||||
const GymLinkHeader({super.key, required this.title});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.arrow_back)),
|
||||
Text(title, style: Theme.of(context).textTheme.titleLarge),
|
||||
],
|
||||
),
|
||||
const Divider(thickness: 1, height: 0),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
79
lib/components/history_item_card.dart
Normal file
79
lib/components/history_item_card.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
|
||||
enum OrderStatus { created, inProgress, completed, canceled }
|
||||
|
||||
Map<OrderStatus, String> orderStatusMap = {
|
||||
OrderStatus.created: 'Создан',
|
||||
OrderStatus.inProgress: 'В обработке',
|
||||
OrderStatus.completed: 'Завершен',
|
||||
OrderStatus.canceled: 'Отменен',
|
||||
};
|
||||
|
||||
class HistoryItemCard extends StatelessWidget {
|
||||
final String id;
|
||||
final String cost;
|
||||
final String date;
|
||||
final Image image;
|
||||
final OrderStatus status;
|
||||
|
||||
const HistoryItemCard({
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.cost,
|
||||
required this.date,
|
||||
required this.status,
|
||||
required this.image,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsetsDirectional.symmetric(horizontal: 10, vertical: 10),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
minHeight: 100,
|
||||
maxHeight: 200,
|
||||
minWidth: 400,
|
||||
maxWidth: 600,
|
||||
),
|
||||
child: Card(
|
||||
elevation: 4,
|
||||
color: const Color(0xFFF2F3F9),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
image,
|
||||
const SizedBox(width: 20),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MarkdownBody(
|
||||
data: '### Заказ **№$id** от $date',
|
||||
),
|
||||
MarkdownBody(
|
||||
data: 'Статус: **${orderStatusMap[status]}**'),
|
||||
MarkdownBody(data: 'Сумма: **\$$cost**'),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
50
lib/components/item_card.dart
Normal file
50
lib/components/item_card.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
267
lib/main.dart
267
lib/main.dart
@@ -3,13 +3,18 @@ import 'dart:js_interop' as js;
|
||||
import 'dart:js_interop_unsafe' as js_util;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gymlink_module_web/components/app_bar.dart';
|
||||
import 'package:gymlink_module_web/components/item_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() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
enum DemoScreen { counter, textField }
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@@ -18,11 +23,48 @@ class MyApp extends StatefulWidget {
|
||||
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":
|
||||
"that name factory say string eaten order harbor easier said tone now floor nest it comfortable such difficulty labor bridge fact market women badly chamber heading forest allow shirt possibly story strip elephant extra even joy lungs than low discussion barn rapidly evidence is stream crew let more sold bag river triangle court slept knowledge flat package research balloon station underline careful market better make curious secret boy poor captured creature harder public tool ring subject charge planet tone scientist piece page stone support bush way feathers summer describe back should said complex song giant his that name factory say string eaten order harbor easier said tone now floor nest it comfortable such difficulty labor bridge fact market women badly chamber heading forest allow shirt possibly story strip elephant extra even joy lungs than low discussion barn rapidly evidence is stream crew let more sold bag river triangle court slept knowledge flat package research balloon station underline careful market better make curious secret boy poor captured creature harder public tool ring subject charge planet tone scientist piece page stone support bush way feathers summer describe back should said complex song giant his that name factory say string eaten order harbor easier said tone now floor nest it comfortable such difficulty labor bridge fact market women badly chamber heading forest allow shirt possibly story strip elephant extra even joy lungs than low discussion barn rapidly evidence is stream crew let more sold bag river triangle court slept knowledge flat package research balloon station underline careful market better make curious secret boy poor captured creature harder public tool ring subject charge planet tone scientist piece page stone support bush way feathers summer describe back should said complex song giant his that name factory say string eaten order harbor easier said tone now floor nest it comfortable such difficulty labor bridge fact market women badly chamber heading forest allow shirt possibly story strip elephant extra even joy lungs than low discussion barn rapidly evidence is stream crew let more sold bag river triangle court slept knowledge flat package research balloon station underline careful market better make curious secret boy poor captured creature harder public tool ring subject charge planet tone scientist piece page stone support bush way feathers summer describe back should said complex song giant his",
|
||||
"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()
|
||||
class _MyAppState extends State<MyApp> {
|
||||
final _streanController = StreamController<void>.broadcast();
|
||||
DemoScreen _currentDemoScreen = DemoScreen.counter;
|
||||
int _counterScreenCount = 0;
|
||||
final _streamController = StreamController<void>.broadcast();
|
||||
bool _isLoading = true;
|
||||
|
||||
@override
|
||||
@@ -35,39 +77,17 @@ class _MyAppState extends State<MyApp> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_streanController.close();
|
||||
_streamController.close();
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Aboba app',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.red),
|
||||
),
|
||||
title: 'GymLink Module',
|
||||
theme: myTheme,
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: demoScreenRouter(_currentDemoScreen),
|
||||
home: MainPage(isLoading: _isLoading),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -79,60 +99,41 @@ class _MyAppState extends State<MyApp> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget demoScreenRouter(DemoScreen which) {
|
||||
switch (which) {
|
||||
case DemoScreen.counter:
|
||||
return CounterDemo(
|
||||
title: 'Counter',
|
||||
numToDisplay: _counterScreenCount,
|
||||
incrementHandler: increment,
|
||||
isLoading: _isLoading);
|
||||
case DemoScreen.textField:
|
||||
return const TextFieldDemo(title: 'Nasdfs');
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
class MainPage extends StatefulWidget {
|
||||
final bool isLoading;
|
||||
|
||||
const CounterDemo(
|
||||
{super.key,
|
||||
required this.title,
|
||||
required this.numToDisplay,
|
||||
required this.incrementHandler,
|
||||
required this.isLoading});
|
||||
const MainPage({
|
||||
super.key,
|
||||
required this.isLoading,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CounterDemo> createState() => _CounterDemoState();
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
class _CounterDemoState extends State<CounterDemo> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: widget.isLoading
|
||||
? null
|
||||
: AppBar(
|
||||
title: Row(
|
||||
appBar: widget.isLoading ? null : const GymLinkAppBar(),
|
||||
body: widget.isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
@@ -141,86 +142,122 @@ class _CounterDemoState extends State<CounterDemo> {
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
suffixIcon: const Icon(
|
||||
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.blue,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
),
|
||||
),
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => const BasketPage(),
|
||||
));
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
minimumSize: const Size(50, kMinInteractiveDimension),
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
shape: const CircleBorder(
|
||||
side: BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 2,
|
||||
color: Colors.black,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.shopping_basket,
|
||||
color: Colors.white,
|
||||
size: 36,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => const HistoryPage(),
|
||||
));
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
minimumSize: const Size(50, kMinInteractiveDimension),
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
shape: const CircleBorder(
|
||||
side: BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 2,
|
||||
color: Colors.black,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.history,
|
||||
color: Colors.white,
|
||||
size: 36,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
body: widget.isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Здесь будут товары',
|
||||
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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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()),
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
249
lib/pages/basket.dart
Normal file
249
lib/pages/basket.dart
Normal file
@@ -0,0 +1,249 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gymlink_module_web/components/app_bar.dart';
|
||||
import 'package:gymlink_module_web/components/basket_item_card.dart';
|
||||
import 'package:gymlink_module_web/components/heading.dart';
|
||||
import 'package:gymlink_module_web/tools/prefs.dart';
|
||||
|
||||
List<Map<String, dynamic>> cart = [
|
||||
{
|
||||
"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"
|
||||
}
|
||||
];
|
||||
|
||||
//TODO: Сделать правильное удаление из корзины по одному
|
||||
class BasketPage extends StatefulWidget {
|
||||
const BasketPage({super.key});
|
||||
|
||||
@override
|
||||
State<BasketPage> createState() => _BasketPageState();
|
||||
}
|
||||
|
||||
class _BasketPageState extends State<BasketPage> {
|
||||
List<Map<String, dynamic>> cartItems = [];
|
||||
int totalPrice = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
getCart().then((value) {
|
||||
setState(() {
|
||||
cartItems = cart
|
||||
.where((element) => value.any((e) => e['id'] == element['id']))
|
||||
.toList();
|
||||
totalPrice =
|
||||
cartItems.fold(0, (sum, item) => sum + int.parse(item['price']));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void removeItem(String id) async {
|
||||
setState(() {
|
||||
cartItems.removeWhere((element) => element['id'] == id);
|
||||
totalPrice =
|
||||
cartItems.fold(0, (sum, item) => sum + int.parse(item['price']));
|
||||
});
|
||||
await removeItemFromCart(id);
|
||||
}
|
||||
|
||||
Future<void> _deleteItemAlert(String id, String name) async {
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Удаление из корзины'),
|
||||
content: SingleChildScrollView(
|
||||
child: ListBody(
|
||||
children: [
|
||||
Text('Вы действительно хотите убрать "$name" из корзины?'),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('Отмена'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('Удалить'),
|
||||
onPressed: () {
|
||||
removeItem(id);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _clearCartAlert() async {
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Очистка корзины'),
|
||||
content: const SingleChildScrollView(
|
||||
child: ListBody(
|
||||
children: [
|
||||
Text('Вы действительно хотите очистить корзину?'),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('Отмена'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('Очистить'),
|
||||
onPressed: () {
|
||||
clearCart();
|
||||
setState(() {
|
||||
cartItems = [];
|
||||
});
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: const GymLinkAppBar(),
|
||||
body: Column(
|
||||
children: [
|
||||
const GymLinkHeader(title: "Корзина"),
|
||||
cartItems.isEmpty
|
||||
? Expanded(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Корзина пуста',
|
||||
style: Theme.of(context).textTheme.bodyLarge),
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(50)),
|
||||
),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Вернуться назад'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: cartItems.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = cartItems[index];
|
||||
return BasketItemCard(
|
||||
name: item['name'],
|
||||
price: item['price'],
|
||||
id: item['id'],
|
||||
image: Image.asset(
|
||||
item['image'],
|
||||
width: 50,
|
||||
),
|
||||
onTap: () =>
|
||||
_deleteItemAlert(item['id'], item['name']),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.symmetric(
|
||||
horizontal: 10, vertical: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'Итого: $totalPrice',
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(50)),
|
||||
),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Оформить заказ'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
onPressed: _clearCartAlert,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(50))),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Очистить корзину'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 50),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
173
lib/pages/detail.dart
Normal file
173
lib/pages/detail.dart
Normal file
@@ -0,0 +1,173 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gymlink_module_web/components/app_bar.dart';
|
||||
import 'package:gymlink_module_web/components/heading.dart';
|
||||
import 'package:gymlink_module_web/tools/prefs.dart';
|
||||
|
||||
//TODO: Сделать получение инфы через объект
|
||||
class DetailPage extends StatefulWidget {
|
||||
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
|
||||
State<DetailPage> createState() => _DetailPageState();
|
||||
}
|
||||
|
||||
class _DetailPageState extends State<DetailPage> {
|
||||
bool isInCart = false;
|
||||
int quantity = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
getCart().then((value) {
|
||||
setState(() {
|
||||
isInCart = value.any((element) => element['id'] == widget.id);
|
||||
if (isInCart) {
|
||||
quantity = value
|
||||
.firstWhere((element) => element['id'] == widget.id)['count'];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildButton() {
|
||||
if (!isInCart) {
|
||||
return ElevatedButton(
|
||||
onPressed: () async {
|
||||
await addItemToCart(widget.id);
|
||||
setState(() {
|
||||
isInCart = true;
|
||||
quantity = 1;
|
||||
});
|
||||
},
|
||||
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('Добавить в корзину'),
|
||||
);
|
||||
} else {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.remove),
|
||||
onPressed: () async {
|
||||
await removeItemFromCart(widget.id);
|
||||
setState(() {
|
||||
if (quantity > 1) {
|
||||
quantity--;
|
||||
} else {
|
||||
isInCart = false;
|
||||
quantity = 0;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
Text('$quantity'),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () async {
|
||||
await addItemToCart(widget.id);
|
||||
setState(() {
|
||||
quantity++;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: const GymLinkAppBar(),
|
||||
body: Column(mainAxisAlignment: MainAxisAlignment.start, children: [
|
||||
GymLinkHeader(title: '${widget.name} - ${widget.id}'),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: SizedBox(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
widget.image,
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsetsDirectional.fromSTEB(0, 30, 60, 60),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
minWidth: 340,
|
||||
maxWidth: 340,
|
||||
maxHeight: 600,
|
||||
),
|
||||
child: Card(
|
||||
elevation: 4,
|
||||
color: const Color(0xFFF2F3F9),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.fromSTEB(
|
||||
20, 15, 10, 15),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
minHeight: 100,
|
||||
),
|
||||
child: Text(
|
||||
widget.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(
|
||||
'Стоимость ${widget.price}',
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
_buildButton()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
80
lib/pages/order_history.dart
Normal file
80
lib/pages/order_history.dart
Normal file
@@ -0,0 +1,80 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gymlink_module_web/components/app_bar.dart';
|
||||
import 'package:gymlink_module_web/components/heading.dart';
|
||||
import 'package:gymlink_module_web/components/history_item_card.dart';
|
||||
|
||||
List<Map<String, String>> orders = [
|
||||
{
|
||||
"image": "product.png",
|
||||
"price": "120",
|
||||
"id": "34fa3126-bfaf-5dec-8f4a-b246c097ef73",
|
||||
"date": "11.09.2001"
|
||||
},
|
||||
{
|
||||
"image": "product.png",
|
||||
"price": "150",
|
||||
"id": "34a26e82-7656-5e98-a44a-c2d01d0b1ad1123",
|
||||
"date": "11.09.2001",
|
||||
},
|
||||
{
|
||||
"image": "product.png",
|
||||
"price": "250",
|
||||
"id": "4fb204b7-3f9e-52a2-bed1-415c00a31a37123",
|
||||
"date": "11.09.2001",
|
||||
},
|
||||
{
|
||||
"image": "product.png",
|
||||
"price": "300",
|
||||
"id": "09b2f5bb-683e-5c39-ae89-b8e152fa8bcf123",
|
||||
"date": "11.09.2001",
|
||||
},
|
||||
{
|
||||
"image": "product.png",
|
||||
"price": "100",
|
||||
"id": "cd1b6817-db94-5394-be1d-af88af79749f123",
|
||||
"date": "11.09.2001",
|
||||
}
|
||||
];
|
||||
|
||||
class HistoryPage extends StatelessWidget {
|
||||
const HistoryPage({
|
||||
super.key,
|
||||
});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: const GymLinkAppBar(),
|
||||
body: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
const GymLinkHeader(title: 'История заказов'),
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: orders.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = orders[index];
|
||||
return HistoryItemCard(
|
||||
id: item['id']!,
|
||||
cost: item['price']!,
|
||||
date: item['date']!,
|
||||
image: Image.asset(
|
||||
item['image']!,
|
||||
width: 50,
|
||||
),
|
||||
status: OrderStatus.completed,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
47
lib/tools/prefs.dart
Normal file
47
lib/tools/prefs.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
Future<void> addItemToCart(String id) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
String cartString = prefs.getString('cart') ?? "[]";
|
||||
List<Map<String, dynamic>> cart =
|
||||
List<Map<String, dynamic>>.from(jsonDecode(cartString) as List<dynamic>);
|
||||
final index = cart.indexWhere((element) => element['id'] == id);
|
||||
if (index == -1) {
|
||||
cart.add({'id': id, 'count': 1});
|
||||
} else {
|
||||
cart[index]['count'] = cart[index]['count']! + 1;
|
||||
}
|
||||
prefs.setString('cart', jsonEncode(cart));
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> getCart() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
String cartString = prefs.getString('cart') ?? "[]";
|
||||
List<Map<String, dynamic>> cart =
|
||||
List<Map<String, dynamic>>.from(jsonDecode(cartString) as List<dynamic>);
|
||||
return cart;
|
||||
}
|
||||
|
||||
Future<void> removeItemFromCart(String id) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
String cartString = prefs.getString('cart') ?? "[]";
|
||||
List<Map<String, dynamic>> cart =
|
||||
List<Map<String, dynamic>>.from(jsonDecode(cartString) as List<dynamic>);
|
||||
cart.removeWhere((element) => element['id'] == id && element['count'] == 1);
|
||||
for (final item in cart) {
|
||||
if (item['id'] == id) {
|
||||
item['count'] = item['count']! - 1;
|
||||
if (item['count'] == 0) {
|
||||
cart.remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
prefs.setString('cart', jsonEncode(cart));
|
||||
}
|
||||
|
||||
Future<void> clearCart() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setString('cart', "[]");
|
||||
}
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
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
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import shared_preferences_foundation
|
||||
import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
}
|
||||
|
||||
206
pubspec.lock
206
pubspec.lock
@@ -57,6 +57,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -75,6 +91,11 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -139,6 +160,102 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.5"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -192,6 +309,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.1"
|
||||
url_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.6"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.1"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.5"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -208,5 +389,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.0.0"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.5.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
sdks:
|
||||
dart: ">=3.3.3 <4.0.0"
|
||||
flutter: ">=3.19.0"
|
||||
|
||||
10
pubspec.yaml
10
pubspec.yaml
@@ -1,5 +1,5 @@
|
||||
name: flutter_application_1
|
||||
description: "A new Flutter project."
|
||||
name: gymlink_module_web
|
||||
description: "GymLink Flutter Web Module."
|
||||
# The following line prevents the package from being accidentally published to
|
||||
# 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
|
||||
@@ -35,6 +35,9 @@ dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.6
|
||||
url_launcher: ^6.2.6
|
||||
shared_preferences: ^2.2.3
|
||||
flutter_markdown: ^0.7.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@@ -57,6 +60,9 @@ flutter:
|
||||
# included with your application, so that you can use the icons in
|
||||
# the material Icons class.
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- assets/logo.png
|
||||
- assets/product.png
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
# assets:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#flutter_target {
|
||||
border: 1px solid #aaa;
|
||||
width: 320px;
|
||||
height: 480px;
|
||||
width: 80vw;
|
||||
height: 60vh;
|
||||
border-radius: 0px;
|
||||
transition: all 150ms ease-in;
|
||||
align-self: center;
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
Reference in New Issue
Block a user