diff --git a/lib/components/menubar.dart b/lib/components/menubar.dart index c7d86ee..aa0b49f 100644 --- a/lib/components/menubar.dart +++ b/lib/components/menubar.dart @@ -1,4 +1,7 @@ +import 'dart:html'; + import 'package:flutter/material.dart'; +import 'package:softplayer_web/components/sign_in_form.dart'; /// Flutter code sample for [AppBar]. @@ -15,6 +18,30 @@ class MenuPanel extends StatefulWidget implements PreferredSizeWidget { enum TabName { home, catalog, about } class _MenuPanel extends State { + bool isSignedIn() { + return window.localStorage.containsKey("token"); + } + List accountActions() { + if (isSignedIn()) { + return [ + IconButton( + onPressed: () => print("acc"), + icon: const Icon(Icons.account_circle)) + ]; + } else { + return [ + TextButton( + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) => const SignInForm()); + }, + child: const Text("sign in")), + TextButton(onPressed: () => print("sign up"), child: const Text("sign up")), + ]; + } + } + final String linkCatalog = "catalog"; final String linkAbout = "about"; final String linkHome = "home"; @@ -59,12 +86,9 @@ class _MenuPanel extends State { Navigator.pushNamed(context, "/about"); }), ]), - automaticallyImplyLeading: false, - actions: [ - IconButton( - onPressed: () => print("acc"), icon: const Icon(Icons.account_circle)) - ], backgroundColor: Colors.cyan, + automaticallyImplyLeading: false, + actions: accountActions(), ); } } diff --git a/lib/components/sign_in_form.dart b/lib/components/sign_in_form.dart new file mode 100644 index 0000000..5a75733 --- /dev/null +++ b/lib/components/sign_in_form.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; + +class SignInForm extends StatefulWidget { + const SignInForm({super.key}); + + @override + State createState() => _SignInFormState(); +} + +class _SignInFormState extends State { + final _formKey = GlobalKey(); + static const dialogName = "Sign In"; + @override + Widget build(BuildContext context) => AlertDialog( + title: const Text(dialogName), + content: Form( + key: _formKey, + child: Center( + child: Column(children: [ + TextFormField( + autofocus: true, + decoration: const InputDecoration( + hintText: "Enter your username or email", + icon: Icon(Icons.account_circle), + ), + ), + TextFormField( + obscureText: true, + decoration: const InputDecoration( + hintText: "Enter your password", + icon: Icon(Icons.password), + ), + ), + ]))), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, 'Cancel'), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + // Validate returns true if the form is valid, or false otherwise. + if (_formKey.currentState!.validate()) { + // If the form is valid, display a snackbar. In the real world, + // you'd often call a server or save the information in a database. + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(_formKey.toString())), + ); + } + }, + child: const Text('OK'), + ), + ], + ); +} diff --git a/lib/helpers/page_wrapper.dart b/lib/helpers/page_wrapper.dart new file mode 100644 index 0000000..28e9c8f --- /dev/null +++ b/lib/helpers/page_wrapper.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:softplayer_web/components/menubar.dart'; + +class PageWrapper extends StatelessWidget{ + final Widget child; + final MenuPanel appBar; + const PageWrapper({ + super.key, + required this.child, + required this.appBar + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar, + body: child, + ); + } + +} diff --git a/lib/main.dart b/lib/main.dart index 6e52176..952937d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,54 +1,42 @@ import 'package:flutter/material.dart'; +import 'package:grpc/grpc_web.dart'; +import 'package:softplayer_web/components/menubar.dart'; +import 'package:softplayer_web/helpers/page_wrapper.dart'; import 'package:softplayer_web/pages/about.dart'; import 'package:softplayer_web/pages/catalog.dart'; import 'package:softplayer_web/pages/home.dart'; -// import 'package:grpc/grpc.dart'; -// import 'package:softplayer_dart_proto/accounts/accounts_v1.pb.dart'; -// import 'package:softplayer_dart_proto/main.dart'; -// import 'package:grpc/grpc_web.dart'; void main() async { -// GrpcWebClientChannel channel = GrpcWebClientChannel.xhr(Uri.parse('http://softplayer.badhouseplants.net:80')); -// final stub = AccountsClient(channel); -// final accWithPassword = AccountWithPassword( -// data: AccountData( -// name: "test", -// email: "test@test.test", -// ), -// accountPassword: AccountPassword(password: "test"), -// ); -// -// try { -// final response = await stub.signUp( -// accWithPassword, -// ); -// print('Greeter client received: ${response}'); -// } catch (e) { -// print('Caught error: $e'); -// } - runApp(const MyApp()); + const String backendURL = String.fromEnvironment( + 'SOFTPLAYER_BACKEND_URL', + defaultValue: 'http://softplayer.badhouseplants.net:8080', + ); + GrpcWebClientChannel grpcChannel = GrpcWebClientChannel.xhr(Uri.parse(backendURL)); + + runApp(MyApp(channel: grpcChannel)); } class MyApp extends StatelessWidget { - const MyApp({super.key}); - - // This widget is the root of your application. + const MyApp({super.key, required this.channel}); + + // A channel that should be used to fire grpc calls + final GrpcWebClientChannel channel; + @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, - title: 'Flutter Demo', + title: 'Softplayer', routes: { - '/': (context) => const HomePage(), - '/catalog': (context) => const CatalogPage(), - '/about': (context) => const AboutPage(), + '/': (context) => PageWrapper( + child: HomePage(), + appBar: MenuPanel(tab: TabName.home), + ), }, - theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), - //home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } diff --git a/lib/pages/catalog.dart b/lib/pages/catalog.dart index 56ee745..5023d83 100644 --- a/lib/pages/catalog.dart +++ b/lib/pages/catalog.dart @@ -1,11 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:grpc/grpc_web.dart'; import 'package:softplayer_web/api/third_party/chartmuseum.dart'; import 'package:softplayer_web/components/catalog_card.dart'; import 'package:softplayer_web/components/menubar.dart'; import 'package:softplayer_web/models/catalog_entry.dart'; class CatalogPage extends StatefulWidget { - const CatalogPage({super.key}); + final GrpcWebClientChannel grpcChannel; + const CatalogPage({ + super.key, + required this.grpcChannel, + }); final String title = "catalog"; @override diff --git a/lib/pages/home.dart b/lib/pages/home.dart index de01fe4..85e242f 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -1,45 +1,25 @@ import 'package:flutter/material.dart'; -import 'package:softplayer_web/components/menubar.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); - final String title = "home"; - + static String title = "home"; + @override State createState() => _HomePage(); } class _HomePage extends State { - int _counter = 0; - void _incrementCounter() { - setState(() { - _counter++; - }); - } - @override Widget build(BuildContext context) { - return Scaffold( - appBar: const MenuPanel(tab: TabName.home), - body: Center( + return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text( + Text( 'You have pushed the button this many times:', ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.tv), - ), + ) ); } } diff --git a/pubspec.lock b/pubspec.lock index a96f994..5cc5cbf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -85,10 +85,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "50fec96118958b97c727d0d8f67255d3683f16cc1f90d9bc917b5d4fe3abeca9" + sha256: "0978e9a3e45305a80a7210dbeaf79d6ee8bee33f70c8e542dc654c952070217f" url: "https://pub.dev" source: hosted - version: "5.4.2" + version: "5.4.2+1" fake_async: dependency: transitive description: @@ -114,10 +114,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" flutter_test: dependency: "direct dev" description: flutter @@ -135,10 +135,10 @@ packages: dependency: transitive description: name: googleapis_auth - sha256: cafc46446574fd42826aa4cd4d623c94482598fda0a5a5649bf2781bcbc09258 + sha256: "1401a9e55f9e0f565d3eebb18d990290f53a12d38a5f7f0230b112895778a85b" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.5.1" grpc: dependency: "direct main" description: @@ -269,7 +269,7 @@ packages: description: path: "." ref: main - resolved-ref: e13b14a448a17fb0d605a48597e3179fc0d2e196 + resolved-ref: eb11f022be9c1fc5db6e87f3463a1ceb3e04501f url: "https://git.badhouseplants.net/softplayer/softplayer-dart-proto.git" source: git version: "1.0.0+1"