import 'dart:async'; import 'dart:js_interop' as js; import 'dart:js_interop_unsafe' as js_util; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } enum DemoScreen { counter, textField } class MyApp extends StatefulWidget { const MyApp({super.key}); // This widget is the root of your application. @override State createState() => _MyAppState(); } @js.JSExport() class _MyAppState extends State { final _streanController = StreamController.broadcast(); DemoScreen _currentDemoScreen = DemoScreen.counter; int _counterScreenCount = 0; 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() { _streanController.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), ), debugShowCheckedModeBanner: false, home: demoScreenRouter(_currentDemoScreen), ); } @js.JSExport() void onTokenReceived(String token) { if (token == 'token123') { setState(() { _isLoading = false; }); } } 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; final bool isLoading; const CounterDemo( {super.key, required this.title, required this.numToDisplay, required this.incrementHandler, required this.isLoading}); @override State createState() => _CounterDemoState(); } class _CounterDemoState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: widget.isLoading ? null : AppBar( title: Row( children: [ Expanded( child: TextField( decoration: InputDecoration( hintText: 'Search', border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), ), suffixIcon: const Icon( Icons.search, color: Colors.blue, ), ), ), ), 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.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, ), ), ], ), ), body: widget.isLoading ? const Center(child: CircularProgressIndicator()) : const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Здесь будут товары', ), ], ), ), ); } } 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()), ), ), ), ); } }