256 lines
8.5 KiB
Dart
256 lines
8.5 KiB
Dart
import 'dart:async';
|
|
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());
|
|
}
|
|
|
|
class MyApp extends StatefulWidget {
|
|
const MyApp({super.key});
|
|
|
|
// This widget is the root of your application.
|
|
@override
|
|
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()
|
|
class _MyAppState extends State<MyApp> {
|
|
final _streamController = StreamController<void>.broadcast();
|
|
bool _isLoading = true;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
final export = js.createJSInteropWrapper(this);
|
|
js.globalContext['_appState'] = export;
|
|
js.globalContext.callMethod('_stateSet'.toJS);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_streamController.close();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
title: 'GymLink Module',
|
|
theme: myTheme,
|
|
debugShowCheckedModeBanner: false,
|
|
home: MainPage(isLoading: _isLoading),
|
|
);
|
|
}
|
|
|
|
@js.JSExport()
|
|
void onTokenReceived(String token) {
|
|
if (token == 'token123') {
|
|
setState(() {
|
|
_isLoading = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
class MainPage extends StatefulWidget {
|
|
final bool isLoading;
|
|
|
|
const MainPage({
|
|
super.key,
|
|
required this.isLoading,
|
|
});
|
|
|
|
@override
|
|
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';
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
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(
|
|
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),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|