From 1bd7a62d15e281018ad1751f80ce413d304ba709 Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Sat, 25 Feb 2023 20:53:09 -0500 Subject: [PATCH 1/6] Profile Page --- lib/home.dart | 75 +++++---- lib/profile_screen_custom.dart | 295 +++++++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+), 38 deletions(-) create mode 100644 lib/profile_screen_custom.dart diff --git a/lib/home.dart b/lib/home.dart index b712f5c..1ef0a3f 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:flutterfire_ui/auth.dart'; import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart'; - +import 'profile_screen_custom.dart'; import 'main_screen.dart'; class HomeScreen extends StatefulWidget { - const HomeScreen({ Key? key }) : super(key: key); + const HomeScreen({Key? key}) : super(key: key); @override _HomeScreenState createState() => _HomeScreenState(); @@ -12,25 +13,21 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { late PersistentTabController _controller; - @override + @override void initState() { super.initState(); _controller = PersistentTabController(); } + List _buildScreens() => [ const MainScreen(), const MainScreen(), - const MainScreen(), + const ProfileScreenCustom(), const MainScreen(), ]; List _navBarsItems() => [ - PersistentBottomNavBarItem( - icon: const Icon(Icons.shopping_cart), - title: "Buy", - activeColorPrimary: Colors.blue, - inactiveColorPrimary: Colors.grey, - inactiveColorSecondary: Colors.purple), + PersistentBottomNavBarItem(icon: const Icon(Icons.shopping_cart), title: "Buy", activeColorPrimary: Colors.blue, inactiveColorPrimary: Colors.grey, inactiveColorSecondary: Colors.purple), PersistentBottomNavBarItem( icon: const Icon(Icons.attach_money), title: "Sell", @@ -59,36 +56,38 @@ class _HomeScreenState extends State { ), ), ]; - + @override Widget build(BuildContext context) { return PersistentTabView( - context, - controller: _controller, - screens: _buildScreens(), - items: _navBarsItems(), - confineInSafeArea: true, - backgroundColor: Colors.white, // Default is Colors.white. - handleAndroidBackButtonPress: true, // Default is true. - resizeToAvoidBottomInset: true, // This needs to be true if you want to move up the screen when keyboard appears. Default is true. - stateManagement: true, // Default is true. - hideNavigationBarWhenKeyboardShows: true, // Recommended to set 'resizeToAvoidBottomInset' as true while using this argument. Default is true. - decoration: NavBarDecoration( - borderRadius: BorderRadius.circular(10.0), - colorBehindNavBar: Colors.white, - ), - popAllScreensOnTapOfSelectedTab: true, - popActionScreens: PopActionScreensType.all, - itemAnimationProperties: const ItemAnimationProperties( // Navigation Bar's items animation properties. - duration: Duration(milliseconds: 200), - curve: Curves.ease, - ), - screenTransitionAnimation: const ScreenTransitionAnimation( // Screen transition animation on change of selected tab. - animateTabTransition: true, - curve: Curves.ease, - duration: Duration(milliseconds: 200), - ), - navBarStyle: NavBarStyle.style13, // Choose the nav bar style with this property. + context, + controller: _controller, + screens: _buildScreens(), + items: _navBarsItems(), + confineInSafeArea: true, + backgroundColor: Colors.white, // Default is Colors.white. + handleAndroidBackButtonPress: true, // Default is true. + resizeToAvoidBottomInset: true, // This needs to be true if you want to move up the screen when keyboard appears. Default is true. + stateManagement: true, // Default is true. + hideNavigationBarWhenKeyboardShows: true, // Recommended to set 'resizeToAvoidBottomInset' as true while using this argument. Default is true. + decoration: NavBarDecoration( + borderRadius: BorderRadius.circular(10.0), + colorBehindNavBar: Colors.white, + ), + popAllScreensOnTapOfSelectedTab: true, + popActionScreens: PopActionScreensType.all, + itemAnimationProperties: const ItemAnimationProperties( + // Navigation Bar's items animation properties. + duration: Duration(milliseconds: 200), + curve: Curves.ease, + ), + screenTransitionAnimation: const ScreenTransitionAnimation( + // Screen transition animation on change of selected tab. + animateTabTransition: true, + curve: Curves.ease, + duration: Duration(milliseconds: 200), + ), + navBarStyle: NavBarStyle.style13, // Choose the nav bar style with this property. ); } -} \ No newline at end of file +} diff --git a/lib/profile_screen_custom.dart b/lib/profile_screen_custom.dart new file mode 100644 index 0000000..964e273 --- /dev/null +++ b/lib/profile_screen_custom.dart @@ -0,0 +1,295 @@ +// Copyright 2022, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:firebase_auth/firebase_auth.dart' show ActionCodeSettings, FirebaseAuth, FirebaseAuthException, User; +import 'package:flutter/cupertino.dart' hide Title; +import 'package:flutterfire_ui/i10n.dart'; +import 'package:flutter/material.dart' hide Title; +import 'package:flutterfire_ui/auth.dart'; +import 'package:flutterfire_ui/src/auth/widgets/internal/loading_button.dart'; + +import 'package:flutterfire_ui/src/auth/widgets/internal/universal_button.dart'; + +import 'package:flutterfire_ui/src/auth/screens/internal/multi_provider_screen.dart'; + +import 'package:flutterfire_ui/src/auth/widgets/internal/rebuild_scope.dart'; +import 'package:flutterfire_ui/src/auth/widgets/internal/subtitle.dart'; +import 'package:flutterfire_ui/src/auth/widgets/internal/universal_icon_button.dart'; + +class EditButton extends StatelessWidget { + final bool isEditing; + final VoidCallback? onPressed; + + const EditButton({ + Key? key, + required this.isEditing, + this.onPressed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return UniversalIconButton( + materialIcon: isEditing ? Icons.check : Icons.edit, + cupertinoIcon: isEditing ? CupertinoIcons.check_mark : CupertinoIcons.pen, + color: theme.colorScheme.secondary, + onPressed: () { + onPressed?.call(); + }, + ); + } +} + +class EmailVerificationBadge extends StatefulWidget { + final FirebaseAuth auth; + final ActionCodeSettings? actionCodeSettings; + const EmailVerificationBadge({ + Key? key, + required this.auth, + this.actionCodeSettings, + }) : super(key: key); + + @override + State createState() => _EmailVerificationBadgeState(); +} + +class _EmailVerificationBadgeState extends State { + late final service = EmailVerificationService(widget.auth) + ..addListener(() { + setState(() {}); + }) + ..reload(); + + EmailVerificationState get state => service.state; + + User get user { + return widget.auth.currentUser!; + } + + TargetPlatform get platform { + return Theme.of(context).platform; + } + + @override + Widget build(BuildContext context) { + if (state == EmailVerificationState.dismissed || state == EmailVerificationState.unresolved || state == EmailVerificationState.verified) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.only(top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.yellow, + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Subtitle( + text: state == EmailVerificationState.sent || state == EmailVerificationState.pending ? 'Verification email sent' : 'Email is not verified', + fontWeight: FontWeight.bold, + ), + if (state == EmailVerificationState.pending) ...[ + const SizedBox(height: 8), + const Text( + 'Please check your email and click the link to verify your email address.', + ), + ] + ], + ), + ), + ), + const SizedBox(height: 16), + if (state == EmailVerificationState.pending) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + LoadingIndicator(size: 16, borderWidth: 0.5), + SizedBox(width: 16), + Text('Waiting for email verification'), + ], + ) + else + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (state != EmailVerificationState.sent && state != EmailVerificationState.sending) + UniversalButton( + variant: ButtonVariant.text, + color: Theme.of(context).colorScheme.error, + text: 'Dismiss', + onPressed: () { + setState(service.dismiss); + }, + ), + if (state != EmailVerificationState.sent) + LoadingButton( + isLoading: state == EmailVerificationState.sending, + label: 'Send verification email', + onTap: () { + service.sendVerificationEmail( + platform, + widget.actionCodeSettings, + ); + }, + ) + else + UniversalButton( + variant: ButtonVariant.text, + text: 'Ok', + onPressed: () { + setState(service.dismiss); + }, + ) + ], + ) + ], + ), + ); + } +} + +class ProfileScreenCustom extends MultiProviderScreen { + final List children; + final Color? avatarPlaceholderColor; + final ShapeBorder? avatarShape; + final double? avatarSize; + final List? actions; + final AppBar? appBar; + final CupertinoNavigationBar? cupertinoNavigationBar; + final ActionCodeSettings? actionCodeSettings; + final Set? styles; + + const ProfileScreenCustom({ + Key? key, + FirebaseAuth? auth, + List? providerConfigs, + this.avatarPlaceholderColor, + this.avatarShape, + this.avatarSize, + this.children = const [], + this.actions, + this.appBar, + this.cupertinoNavigationBar, + this.actionCodeSettings, + this.styles, + }) : super(key: key, providerConfigs: providerConfigs, auth: auth); + + Future _reauthenticate(BuildContext context) { + return showReauthenticateDialog( + context: context, + providerConfigs: providerConfigs, + auth: auth, + onSignedIn: () => Navigator.of(context).pop(true), + ); + } + + List getLinkedProviders(User user) { + return providerConfigs.where((config) => user.isProviderLinked(config.providerId)).toList(); + } + + List getAvailableProviders(User user) { + return providerConfigs.where((config) => !user.isProviderLinked(config.providerId)).toList(); + } + + @override + Widget build(BuildContext context) { + return FlutterFireUITheme( + styles: styles ?? const {}, + child: Builder(builder: buildPage), + ); + } + + Widget buildPage(BuildContext context) { + final isCupertino = CupertinoUserInterfaceLevel.maybeOf(context) != null; + final providersScopeKey = RebuildScopeKey(); + final emailVerificationScopeKey = RebuildScopeKey(); + + final user = auth.currentUser!; + + final content = Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Align( + child: UserAvatar( + auth: auth, + placeholderColor: avatarPlaceholderColor, + shape: avatarShape, + size: avatarSize, + ), + ), + Align(child: EditableUserDisplayName(auth: auth)), + if (!user.emailVerified) ...[ + RebuildScope( + builder: (context) { + if (user.emailVerified) { + return const SizedBox.shrink(); + } + + return EmailVerificationBadge( + auth: auth, + actionCodeSettings: actionCodeSettings, + ); + }, + scopeKey: emailVerificationScopeKey, + ), + ], + ...children, + const SizedBox(height: 16), + SignOutButton( + auth: auth, + variant: ButtonVariant.outlined, + ), + const SizedBox(height: 8), + ], + ); + final body = Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: LayoutBuilder( + builder: (context, constraints) { + if (constraints.maxWidth > 500) { + return ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 500), + child: content, + ); + } else { + return content; + } + }, + ), + ), + ); + + Widget child = SafeArea(child: SingleChildScrollView(child: body)); + + if (isCupertino) { + child = CupertinoPageScaffold( + navigationBar: cupertinoNavigationBar, + child: SafeArea( + child: SingleChildScrollView(child: child), + ), + ); + } else { + child = Scaffold( + appBar: appBar, + body: SafeArea( + child: SingleChildScrollView(child: body), + ), + ); + } + + return FlutterFireUIActions( + actions: actions ?? const [], + child: child, + ); + } +} From a0383a7854e07ad1702662323476a29604c02d07 Mon Sep 17 00:00:00 2001 From: NATHANIEL ENDICK Date: Sat, 25 Feb 2023 21:01:16 -0500 Subject: [PATCH 2/6] Merge branch 'master' of https://github.com/SoPat712/RUSwipeShare --- lib/home.dart | 19 ++++++++++++++----- lib/main.dart | 26 +++++++++++++------------- lib/sell.dart | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 lib/sell.dart diff --git a/lib/home.dart b/lib/home.dart index 1ef0a3f..7162f95 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutterfire_ui/auth.dart'; import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart'; +import 'package:ruswipeshare/sell.dart'; import 'profile_screen_custom.dart'; import 'main_screen.dart'; @@ -21,13 +22,18 @@ class _HomeScreenState extends State { List _buildScreens() => [ const MainScreen(), - const MainScreen(), + const SellScreen(), const ProfileScreenCustom(), const MainScreen(), ]; List _navBarsItems() => [ - PersistentBottomNavBarItem(icon: const Icon(Icons.shopping_cart), title: "Buy", activeColorPrimary: Colors.blue, inactiveColorPrimary: Colors.grey, inactiveColorSecondary: Colors.purple), + PersistentBottomNavBarItem( + icon: const Icon(Icons.shopping_cart), + title: "Buy", + activeColorPrimary: Colors.blue, + inactiveColorPrimary: Colors.grey, + inactiveColorSecondary: Colors.purple), PersistentBottomNavBarItem( icon: const Icon(Icons.attach_money), title: "Sell", @@ -67,9 +73,11 @@ class _HomeScreenState extends State { confineInSafeArea: true, backgroundColor: Colors.white, // Default is Colors.white. handleAndroidBackButtonPress: true, // Default is true. - resizeToAvoidBottomInset: true, // This needs to be true if you want to move up the screen when keyboard appears. Default is true. + resizeToAvoidBottomInset: + true, // This needs to be true if you want to move up the screen when keyboard appears. Default is true. stateManagement: true, // Default is true. - hideNavigationBarWhenKeyboardShows: true, // Recommended to set 'resizeToAvoidBottomInset' as true while using this argument. Default is true. + hideNavigationBarWhenKeyboardShows: + true, // Recommended to set 'resizeToAvoidBottomInset' as true while using this argument. Default is true. decoration: NavBarDecoration( borderRadius: BorderRadius.circular(10.0), colorBehindNavBar: Colors.white, @@ -87,7 +95,8 @@ class _HomeScreenState extends State { curve: Curves.ease, duration: Duration(milliseconds: 200), ), - navBarStyle: NavBarStyle.style13, // Choose the nav bar style with this property. + navBarStyle: + NavBarStyle.style13, // Choose the nav bar style with this property. ); } } diff --git a/lib/main.dart b/lib/main.dart index 9b07f7b..cb31596 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,25 +5,25 @@ import 'firebase_options.dart'; import 'auth_gate.dart'; void main() async { - WidgetsFlutterBinding.ensureInitialized(); + WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); runApp(const MyApp()); } class MyApp extends StatelessWidget { - - const MyApp({super.key}); - @override - Widget build(BuildContext context) { - return MaterialApp( - theme: ThemeData( - primarySwatch: CustomMaterialColor(200,61,61).mdColor, - ), - home: const AuthGate(), - ); - } + const MyApp({super.key}); + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData( + primarySwatch: CustomMaterialColor(200, 61, 61).mdColor, + ), + home: const AuthGate(), + ); + } } + class CustomMaterialColor { final int r; final int g; @@ -46,4 +46,4 @@ class CustomMaterialColor { }; return MaterialColor(Color.fromRGBO(r, g, b, 1).value, color); } -} \ No newline at end of file +} diff --git a/lib/sell.dart b/lib/sell.dart new file mode 100644 index 0000000..03211d7 --- /dev/null +++ b/lib/sell.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class SellScreen extends StatefulWidget { + const SellScreen({Key? key}) : super(key: key); + + @override + _SellScreenState createState() => _SellScreenState(); +} + +class _SellScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Sell'), + automaticallyImplyLeading: false, + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.store_mall_directory, color: Colors.red), + Expanded( + child: const Text('Place'), + ), + Icon(Icons.access_time, color: Colors.red), + Expanded( + child: const Text('Time'), + ), + Icon(Icons.attach_money, color: Colors.red), + Expanded( + child: const Text('Cost'), + ), + ], + ), + ); + } +} From ba21c70566d415bba299da088df9ad9cc1214ad9 Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Sat, 25 Feb 2023 21:10:05 -0500 Subject: [PATCH 3/6] custom profile fixes --- lib/home.dart | 1 - lib/profile_screen_custom.dart | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/home.dart b/lib/home.dart index 1ef0a3f..c84bda9 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutterfire_ui/auth.dart'; import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart'; import 'profile_screen_custom.dart'; import 'main_screen.dart'; diff --git a/lib/profile_screen_custom.dart b/lib/profile_screen_custom.dart index 964e273..3cf9ffd 100644 --- a/lib/profile_screen_custom.dart +++ b/lib/profile_screen_custom.dart @@ -111,10 +111,14 @@ class _EmailVerificationBadgeState extends State { if (state == EmailVerificationState.pending) Row( mainAxisAlignment: MainAxisAlignment.center, - children: const [ - LoadingIndicator(size: 16, borderWidth: 0.5), - SizedBox(width: 16), - Text('Waiting for email verification'), + children: [ + + const SizedBox(width: 16), + Wrap( + children: const [ + Text('Log out and log back in to confirm.'), + ], + ), ], ) else From c61a30cbf53b3f50308106a5d36f845ca2ea8b8d Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Sat, 25 Feb 2023 21:13:53 -0500 Subject: [PATCH 4/6] pfp color red --- lib/profile_screen_custom.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/profile_screen_custom.dart b/lib/profile_screen_custom.dart index 3cf9ffd..fe29e7b 100644 --- a/lib/profile_screen_custom.dart +++ b/lib/profile_screen_custom.dart @@ -225,7 +225,7 @@ class ProfileScreenCustom extends MultiProviderScreen { Align( child: UserAvatar( auth: auth, - placeholderColor: avatarPlaceholderColor, + placeholderColor: Theme.of(context).colorScheme.primary, shape: avatarShape, size: avatarSize, ), From 2dac014064bcd776642a0b0ce5992ba8a5b2b294 Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Sat, 25 Feb 2023 21:46:23 -0500 Subject: [PATCH 5/6] Force PersistentNavBar --- lib/profile_screen_custom.dart | 22 +++++++++++++--------- pubspec.lock | 8 ++++++++ pubspec.yaml | 1 + 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/profile_screen_custom.dart b/lib/profile_screen_custom.dart index fe29e7b..d30657d 100644 --- a/lib/profile_screen_custom.dart +++ b/lib/profile_screen_custom.dart @@ -2,10 +2,13 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// ignore_for_file: implementation_imports + import 'package:firebase_auth/firebase_auth.dart' show ActionCodeSettings, FirebaseAuth, FirebaseAuthException, User; import 'package:flutter/cupertino.dart' hide Title; -import 'package:flutterfire_ui/i10n.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/material.dart' hide Title; +import 'package:flutter_credit_card/flutter_credit_card.dart'; import 'package:flutterfire_ui/auth.dart'; import 'package:flutterfire_ui/src/auth/widgets/internal/loading_button.dart'; @@ -112,7 +115,6 @@ class _EmailVerificationBadgeState extends State { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - const SizedBox(width: 16), Wrap( children: const [ @@ -220,7 +222,7 @@ class ProfileScreenCustom extends MultiProviderScreen { final user = auth.currentUser!; final content = Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + crossAxisAlignment: CrossAxisAlignment.center, children: [ Align( child: UserAvatar( @@ -247,10 +249,13 @@ class ProfileScreenCustom extends MultiProviderScreen { ), ], ...children, - const SizedBox(height: 16), - SignOutButton( - auth: auth, - variant: ButtonVariant.outlined, + const SizedBox(height: 300), + Align( + alignment: Alignment.bottomCenter, + child: SignOutButton( + auth: auth, + variant: ButtonVariant.filled, + ), ), const SizedBox(height: 8), ], @@ -261,8 +266,7 @@ class ProfileScreenCustom extends MultiProviderScreen { child: LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth > 500) { - return ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 500), + return Expanded( child: content, ); } else { diff --git a/pubspec.lock b/pubspec.lock index 4c9d6c4..c4056d9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -206,6 +206,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_credit_card: + dependency: "direct main" + description: + name: flutter_credit_card + sha256: "0fc71e8bfb0e126d2c4247830c04e2acf2b831161411a361e9fa9dc1cc41e605" + url: "https://pub.dev" + source: hosted + version: "3.0.5" flutter_dotenv: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index d8761c8..f84f51f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: flutterfire_ui: ^0.4.3+20 flutter_dotenv: ^5.0.2 persistent_bottom_nav_bar: any + flutter_credit_card: any dev_dependencies: flutter_test: From 1c7a9109181314ad8455cf837f1eaf5769f78b90 Mon Sep 17 00:00:00 2001 From: NATHANIEL ENDICK Date: Sat, 25 Feb 2023 21:46:56 -0500 Subject: [PATCH 6/6] Half done with ui for sell --- lib/sell.dart | 55 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/lib/sell.dart b/lib/sell.dart index 03211d7..f28b608 100644 --- a/lib/sell.dart +++ b/lib/sell.dart @@ -10,6 +10,7 @@ class SellScreen extends StatefulWidget { class _SellScreenState extends State { @override Widget build(BuildContext context) { + TimeOfDay _time = TimeOfDay.now(); return Scaffold( appBar: AppBar( title: const Text('Sell'), @@ -19,9 +20,21 @@ class _SellScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.store_mall_directory, color: Colors.red), - Expanded( - child: const Text('Place'), + const Text('Place'), + ListTile( + title: Text(_time.format(context)), + onTap: () { + Future selectedTime = showTimePicker( + context: context, + initialTime: _time, + ); + setState(() { + selectedTime.then((value) => _time = value!); + _time = TimeOfDay(hour: 10, minute: 00); + }); + }, ), + LocationDropdown(), Icon(Icons.access_time, color: Colors.red), Expanded( child: const Text('Time'), @@ -35,3 +48,41 @@ class _SellScreenState extends State { ); } } + +const List list = [ + 'Brower', + 'BDH', + 'LDH', + 'Neilson', + 'Woody\'s' +]; + +class LocationDropdown extends StatefulWidget { + const LocationDropdown({super.key}); + + @override + State createState() => _LocationDropdownState(); +} + +class _LocationDropdownState extends State { + String dropdownValue = list.first; + + @override + Widget build(BuildContext context) { + return DropdownButton( + value: dropdownValue, + onChanged: (String? value) { + // This is called when the user selects an item. + setState(() { + dropdownValue = value!; + }); + }, + items: list.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ); + } +}