diff --git a/lib/components/app_bar.dart b/lib/components/app_bar.dart index 20ea761..ae798c8 100644 --- a/lib/components/app_bar.dart +++ b/lib/components/app_bar.dart @@ -6,7 +6,7 @@ class GymLinkAppBar extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { return AppBar( - backgroundColor: Colors.white, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, shadowColor: null, automaticallyImplyLeading: false, elevation: 0, diff --git a/lib/components/item_card.dart b/lib/components/item_card.dart index cdd3f01..59f98ce 100644 --- a/lib/components/item_card.dart +++ b/lib/components/item_card.dart @@ -22,7 +22,7 @@ class ProductCard extends StatelessWidget { constraints: const BoxConstraints(minHeight: 200), child: Card( elevation: 3, - color: const Color(0xFFF2F3F9), + color: Theme.of(context).scaffoldBackgroundColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), diff --git a/lib/main.dart b/lib/main.dart index 8c47920..f4eed45 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,15 +1,5 @@ -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'; +import 'package:gymlink_module_web/states/web.dart'; void main() { runApp(const MyApp()); @@ -18,246 +8,6 @@ void main() { class MyApp extends StatefulWidget { const MyApp({super.key}); - // This widget is the root of your application. @override - State createState() => _MyAppState(); -} - -const List> 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 { - final _streamController = StreamController.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 createState() => _MainPageState(); -} - -class _MainPageState extends State { - Future _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: [ - 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 Spacer( - flex: 2, - ), - ElevatedButton( - 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.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(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( - 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), - ), - ), - ), - ); - }, - ), - ), - ], - ), - ); - } + State createState() => MyAppStateWeb(); } diff --git a/lib/main_mobile.dart b/lib/main_mobile.dart new file mode 100644 index 0000000..19e3831 --- /dev/null +++ b/lib/main_mobile.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:gymlink_module_web/states/mobile.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => MyAppStateMobile(); +} diff --git a/lib/pages/detail.dart b/lib/pages/detail.dart index 8e5ca7f..9b463de 100644 --- a/lib/pages/detail.dart +++ b/lib/pages/detail.dart @@ -124,7 +124,7 @@ class _DetailPageState extends State { ), child: Card( elevation: 4, - color: const Color(0xFFF2F3F9), + color: Theme.of(context).scaffoldBackgroundColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), diff --git a/lib/pages/main.dart b/lib/pages/main.dart new file mode 100644 index 0000000..39a0713 --- /dev/null +++ b/lib/pages/main.dart @@ -0,0 +1,207 @@ +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:url_launcher/url_launcher.dart'; + +const List> 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" + } +]; + +class MainPage extends StatefulWidget { + final bool isLoading; + + const MainPage({ + super.key, + required this.isLoading, + }); + + @override + State createState() => _MainPageState(); +} + +class _MainPageState extends State { + Future _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: [ + 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 Spacer( + flex: 2, + ), + ElevatedButton( + 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.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(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( + 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), + ), + ), + ), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/lib/states/mobile.dart b/lib/states/mobile.dart new file mode 100644 index 0000000..1e6dfaf --- /dev/null +++ b/lib/states/mobile.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:gymlink_module_web/main_mobile.dart'; +import 'package:gymlink_module_web/pages/main.dart'; +import 'package:gymlink_module_web/theme.dart'; + +class MyAppStateMobile extends State { + bool _isLoading = true; + ThemeData theme = myTheme; + bool black_theme = false; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'GymLink Module', + theme: theme, + debugShowCheckedModeBanner: false, + home: MainPage(isLoading: _isLoading), + ); + } + + void onTokenReceived(String token) { + if (token == 'token123') { + setState(() { + _isLoading = false; + }); + } + } + + void changeColor(int color) { + setState(() { + black_theme = !black_theme; //FIXME: TEMPORARY + theme = getThemeData(Color(color), black_theme); + }); + } +} diff --git a/lib/states/web.dart b/lib/states/web.dart new file mode 100644 index 0000000..39c6e7b --- /dev/null +++ b/lib/states/web.dart @@ -0,0 +1,57 @@ +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/main.dart'; +import 'package:gymlink_module_web/pages/main.dart'; +import 'package:gymlink_module_web/theme.dart'; + +@js.JSExport() +class MyAppStateWeb extends State { + final _streamController = StreamController.broadcast(); + bool _isLoading = true; + ThemeData theme = myTheme; + bool black_theme = false; + + @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: theme, + debugShowCheckedModeBanner: false, + home: MainPage(isLoading: _isLoading), + ); + } + + @js.JSExport() + void onTokenReceived(String token) { + if (token == 'token123') { + setState(() { + _isLoading = false; + }); + } + } + + @js.JSExport() + void changeColor(int color) { + setState(() { + black_theme = !black_theme; //FIXME: TEMPORARY + theme = getThemeData(Color(color), black_theme); + }); + } +}