Error provider

This commit is contained in:
2024-05-17 16:11:05 +03:00
parent c54176212a
commit 986a9d9bd5
7 changed files with 238 additions and 204 deletions

View File

@@ -1,8 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gymlink_module_web/providers/main.dart';
import 'package:gymlink_module_web/states/web.dart'; import 'package:gymlink_module_web/states/web.dart';
import 'package:provider/provider.dart';
void main() { void main() {
runApp(const MyApp()); runApp(const MyAppWithProvider());
} }
class MyApp extends StatefulWidget { class MyApp extends StatefulWidget {
@@ -11,3 +13,13 @@ class MyApp extends StatefulWidget {
@override @override
State<MyApp> createState() => MyAppStateWeb(); State<MyApp> createState() => MyAppStateWeb();
} }
class MyAppWithProvider extends StatelessWidget {
const MyAppWithProvider({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => GymLinkProvider(), child: const MyApp());
}
}

View File

@@ -4,6 +4,7 @@ import 'package:gymlink_module_web/components/basket_item_card.dart';
import 'package:gymlink_module_web/components/heading.dart'; import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/pages/order_confirmation.dart'; import 'package:gymlink_module_web/pages/order_confirmation.dart';
import 'package:gymlink_module_web/providers/cart.dart'; import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/providers/main.dart';
import 'package:gymlink_module_web/tools/prefs.dart'; import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/routes.dart'; import 'package:gymlink_module_web/tools/routes.dart';
import 'package:lazy_load_scrollview/lazy_load_scrollview.dart'; import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
@@ -77,6 +78,7 @@ class _BasketPageState extends State<BasketPage> {
void _updateCart() { void _updateCart() {
Provider.of<CartProvider>(context, listen: false).updateCartLength(); Provider.of<CartProvider>(context, listen: false).updateCartLength();
Provider.of<GymLinkProvider>(context, listen: false).onTokenReceived('123');
} }
void removeItem(String id) async { void removeItem(String id) async {

View File

@@ -7,6 +7,7 @@ import 'package:gymlink_module_web/pages/basket.dart';
import 'package:gymlink_module_web/pages/detail.dart'; import 'package:gymlink_module_web/pages/detail.dart';
import 'package:gymlink_module_web/pages/order_history.dart'; import 'package:gymlink_module_web/pages/order_history.dart';
import 'package:gymlink_module_web/providers/cart.dart'; import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/providers/main.dart';
import 'package:gymlink_module_web/tools/prefs.dart'; import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/relative.dart'; import 'package:gymlink_module_web/tools/relative.dart';
import 'package:gymlink_module_web/tools/routes.dart'; import 'package:gymlink_module_web/tools/routes.dart';
@@ -54,11 +55,8 @@ const List<Map<String, String>> testData = [
]; ];
class MainPage extends StatefulWidget { class MainPage extends StatefulWidget {
final bool isLoading;
const MainPage({ const MainPage({
super.key, super.key,
required this.isLoading,
}); });
@override @override
@@ -108,177 +106,170 @@ class _MainPageState extends State<MainPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final cartL = context.watch<CartProvider>().cartLength; final cartL = context.watch<CartProvider>().cartLength;
final onError = context.read<GymLinkProvider>().onError;
return Scaffold( return Scaffold(
appBar: widget.isLoading ? null : const GymLinkAppBar(), appBar: const GymLinkAppBar(),
body: widget.isLoading body: Column(
? const Center(child: CircularProgressIndicator()) mainAxisAlignment: MainAxisAlignment.start,
: Column( children: <Widget>[
mainAxisAlignment: MainAxisAlignment.start, Padding(
children: <Widget>[ padding: const EdgeInsets.symmetric(horizontal: 5),
Padding( child: Row(
padding: const EdgeInsets.symmetric(horizontal: 5), mainAxisAlignment: MainAxisAlignment.spaceAround,
child: Row( children: [
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
child: TextField(
onChanged: (value) => setState(() {
searchText = value;
}),
decoration: InputDecoration(
hintText: 'Поиск',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
suffixIcon: Padding(
padding: const EdgeInsets.only(right: 8),
child: ElevatedButton(
onPressed: _onSearch,
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,
),
),
),
),
),
),
getSpacer(context: context, flex: 2),
const SizedBox(
width: 8,
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(CustomPageRoute(
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.black,
width: 1,
),
),
),
child: const Icon(
Icons.history,
color: Colors.white,
size: 24,
),
),
const SizedBox(
width: 10,
)
],
),
),
Expanded( Expanded(
child: LazyLoadScrollView( child: TextField(
onEndOfPage: _onLoad, onChanged: (value) => setState(() {
child: Stack( searchText = value;
children: [ }),
GridView.builder( decoration: InputDecoration(
gridDelegate: hintText: 'Поиск',
SliverGridDelegateWithFixedCrossAxisCount( border: OutlineInputBorder(
crossAxisCount: min( borderRadius: BorderRadius.circular(10),
(MediaQuery.sizeOf(context).width ~/ 200) ),
.toInt(), suffixIcon: Padding(
8), padding: const EdgeInsets.only(right: 8),
child: ElevatedButton(
onPressed: _onSearch,
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,
), ),
itemCount: filteredData.length,
itemBuilder: (context, index) {
final product = filteredData[index];
return ProductCard(
imagePath: Image(
image: Image.network(
'https://rus-sport.net/upload/iblock/311/topb85ez18pq0aavohpa5zipk2sbfxll.jpg')
.image,
width: 50,
),
name: product['name']!,
price: product['price']!,
onTap: () => Navigator.of(context).push(
CustomPageRoute(
builder: (context) => DetailPage(
name: product['name']!,
description: product['details']!,
price: product['price']!,
id: product['id']!,
image: Image(
image: AssetImage(
'assets/${product['image']!}'),
width: 300),
),
),
),
);
},
), ),
], ),
), ),
), ),
), ),
getSpacer(context: context, flex: 2),
const SizedBox(
width: 8,
),
ElevatedButton(
onPressed: () {
onError();
Navigator.of(context).push(CustomPageRoute(
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.black,
width: 1,
),
),
),
child: const Icon(
Icons.history,
color: Colors.white,
size: 24,
),
),
const SizedBox(
width: 10,
)
], ],
), ),
floatingActionButton: !widget.isLoading ),
? SizedBox( Expanded(
height: 80, child: LazyLoadScrollView(
width: 80, onEndOfPage: _onLoad,
child: FittedBox( child: Stack(
child: Stack( children: [
children: [ GridView.builder(
FloatingActionButton( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
onPressed: () => crossAxisCount: min(
Navigator.of(context).push(CustomPageRoute( (MediaQuery.sizeOf(context).width ~/ 200).toInt(), 8),
builder: (context) => const BasketPage(),
)),
backgroundColor: Colors.transparent,
elevation: 0,
child: CircleAvatar(
radius: 25,
backgroundColor: Theme.of(context).primaryColor,
foregroundColor: Colors.white,
child: const Icon(Icons.shopping_cart_outlined)),
), ),
cartL > 0 itemCount: filteredData.length,
? Positioned( itemBuilder: (context, index) {
right: -3, final product = filteredData[index];
bottom: 0, return ProductCard(
child: Card( imagePath: Image(
color: Colors.red, image: Image.network(
child: SizedBox( 'https://rus-sport.net/upload/iblock/311/topb85ez18pq0aavohpa5zipk2sbfxll.jpg')
width: 20, .image,
child: Center( width: 50,
child: Text( ),
cartL.toString(), name: product['name']!,
style: const TextStyle(color: Colors.white), price: product['price']!,
), onTap: () => Navigator.of(context).push(
), CustomPageRoute(
), builder: (context) => DetailPage(
name: product['name']!,
description: product['details']!,
price: product['price']!,
id: product['id']!,
image: Image(
image:
AssetImage('assets/${product['image']!}'),
width: 300),
), ),
) ),
: const SizedBox.shrink(), ),
], );
), },
),
],
), ),
) ),
: null, ),
],
),
floatingActionButton: SizedBox(
height: 80,
width: 80,
child: FittedBox(
child: Stack(
children: [
FloatingActionButton(
onPressed: () => Navigator.of(context).push(CustomPageRoute(
builder: (context) => const BasketPage(),
)),
backgroundColor: Colors.transparent,
elevation: 0,
child: CircleAvatar(
radius: 25,
backgroundColor: Theme.of(context).primaryColor,
foregroundColor: Colors.white,
child: const Icon(Icons.shopping_cart_outlined)),
),
cartL > 0
? Positioned(
right: -3,
bottom: 0,
child: Card(
color: Colors.red,
child: SizedBox(
width: 20,
child: Center(
child: Text(
cartL.toString(),
style: const TextStyle(color: Colors.white),
),
),
),
),
)
: const SizedBox.shrink(),
],
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat, floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
); );
} }

View File

@@ -8,10 +8,17 @@ class GymLinkProvider with ChangeNotifier {
bool get blackTheme => _blackTheme; bool get blackTheme => _blackTheme;
ThemeData _theme = myTheme; ThemeData _theme = myTheme;
ThemeData get theme => _theme; ThemeData get theme => _theme;
void Function() _onError = () => {};
void Function() get onError => _onError;
void onTokenReceived(String token) { void onTokenReceived(String token) {
if (token == 'token123') { if (token == 'token123') {
_isLoading = false; _isLoading = false;
notifyListeners(); notifyListeners();
} else {
_isLoading = true;
notifyListeners();
} }
} }
@@ -25,4 +32,8 @@ class GymLinkProvider with ChangeNotifier {
_theme = theme; _theme = theme;
notifyListeners(); notifyListeners();
} }
void setOnError(void Function() onError) {
_onError = onError;
}
} }

View File

@@ -14,12 +14,14 @@ class MyAppStateMobile extends State<MyApp> {
final isLoading = provider.isLoading; final isLoading = provider.isLoading;
return ChangeNotifierProvider( return ChangeNotifierProvider(
create: (_) => CartProvider(), create: (_) => CartProvider(),
builder: (context, __) => MaterialApp( builder: (context, __) => isLoading
title: 'GymLink Module', ? const Center(child: CircularProgressIndicator())
theme: theme, : MaterialApp(
debugShowCheckedModeBanner: false, title: 'GymLink Module',
home: MainPage(isLoading: isLoading), theme: theme,
), debugShowCheckedModeBanner: false,
home: const MainPage(),
),
); );
}, },
); );

View File

@@ -6,13 +6,13 @@ import 'package:flutter/material.dart';
import 'package:gymlink_module_web/main.dart'; import 'package:gymlink_module_web/main.dart';
import 'package:gymlink_module_web/pages/main.dart'; import 'package:gymlink_module_web/pages/main.dart';
import 'package:gymlink_module_web/providers/cart.dart'; import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/providers/main.dart';
import 'package:gymlink_module_web/theme.dart'; import 'package:gymlink_module_web/theme.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@js.JSExport() @js.JSExport()
class MyAppStateWeb extends State<MyApp> { class MyAppStateWeb extends State<MyApp> {
final _streamController = StreamController<void>.broadcast(); final _streamController = StreamController<void>.broadcast();
bool _isLoading = true;
ThemeData theme = myTheme; ThemeData theme = myTheme;
bool black_theme = false; bool black_theme = false;
@@ -32,31 +32,33 @@ class MyAppStateWeb extends State<MyApp> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<GymLinkProvider>().theme;
final isLoading = context.watch<GymLinkProvider>().isLoading;
return ChangeNotifierProvider( return ChangeNotifierProvider(
create: (_) => CartProvider(), create: (_) => CartProvider(),
child: MaterialApp( child: isLoading
title: 'GymLink Module', ? const Center(child: CircularProgressIndicator())
theme: theme, : MaterialApp(
debugShowCheckedModeBanner: false, title: 'GymLink Module',
home: MainPage(isLoading: _isLoading), theme: theme,
), debugShowCheckedModeBanner: false,
home: const MainPage(),
),
); );
} }
@js.JSExport() @js.JSExport()
void onTokenReceived(String token) { void onTokenReceived(String token) {
if (token == 'token123') { context.read<GymLinkProvider>().onTokenReceived(token);
setState(() {
_isLoading = false;
});
}
} }
@js.JSExport() @js.JSExport()
void changeColor(int color) { void changeColor(int color) {
setState(() { context.read<GymLinkProvider>().changeTheme(color);
black_theme = !black_theme; //FIXME: TEMPORARY }
theme = getThemeData(Color(color), black_theme);
}); @js.JSExport()
void setOnError(void Function() onError) {
context.read<GymLinkProvider>().setOnError(onError);
} }
} }

View File

@@ -1,31 +1,45 @@
(function(){ (function () {
"use strict"; 'use strict';
window._stateSet = function () { window._stateSet = function () {
window._stateSet = function() { window._stateSet = function () {
console.log("Call _stateSet only once"); console.log('Call _stateSet only once');
}; };
let appState = window._appState; let appState = window._appState;
let btn = document.getElementById('token'); let btn = document.getElementById('token');
btn.addEventListener('click', function() { btn.addEventListener('click', function () {
appState.onTokenReceived('token123'); appState.onTokenReceived('token123');
}) });
let colorChangeBtnRed = document.getElementById('colorChangeBtnRed'); let colorChangeBtnRed = document.getElementById('colorChangeBtnRed');
colorChangeBtnRed.addEventListener('click', function() { colorChangeBtnRed.addEventListener('click', function () {
var hexColor = '#FF0000'.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i var hexColor = '#FF0000'
, (m, r, g, b) => '#ff' + r + r + g + g + b + b).substring(1); .replace(
/^#?([a-f\d])([a-f\d])([a-f\d])$/i,
(m, r, g, b) => '#ff' + r + r + g + g + b + b
)
.substring(1);
var numColor = parseInt(hexColor, 16); var numColor = parseInt(hexColor, 16);
appState.changeColor(numColor) appState.changeColor(numColor);
}) });
let colorChangeBtnBlue = document.getElementById('colorChangeBtnBlue'); let colorChangeBtnBlue = document.getElementById('colorChangeBtnBlue');
colorChangeBtnBlue.addEventListener('click', function() { colorChangeBtnBlue.addEventListener('click', function () {
var hexColor = '#0000FF'.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i var hexColor = '#0000FF'
, (m, r, g, b) => '#ff' + r + r + g + g + b + b).substring(1); .replace(
/^#?([a-f\d])([a-f\d])([a-f\d])$/i,
(m, r, g, b) => '#ff' + r + r + g + g + b + b
)
.substring(1);
var numColor = parseInt(hexColor, 16); var numColor = parseInt(hexColor, 16);
appState.changeColor(numColor) appState.changeColor(numColor);
}) });
}
}()); function onError() {
console.error('aboba');
}
appState.setOnError(onError);
};
})();