Loading lib/bottom_nav_bar/widget/bottom_nav_bar.dart +5 −5 Original line number Diff line number Diff line Loading @@ -2,8 +2,9 @@ import 'package:flutter/material.dart'; import 'package:stamped/bottom_nav_bar/model/bottom_nav_bar_item.dart'; import 'package:stamped/pages/collections/collections_page.dart'; import 'package:stamped/pages/home/home_page.dart'; import 'package:stamped/pages/profile/profile_page.dart'; const List<BottomNavBarItem> _NAV_ITEMS = [ final List<BottomNavBarItem> _navItems = [ BottomNavBarItem( label: 'Home', icon: Icon(Icons.home), Loading @@ -29,8 +30,7 @@ const List<BottomNavBarItem> _NAV_ITEMS = [ BottomNavBarItem( label: 'Profile', icon: Icon(Icons.person), // TODO: replace with the profile page child: Placeholder(), child: ProfilePage(), ), ]; Loading @@ -47,10 +47,10 @@ class _BottomNavBarState extends State<BottomNavBar> { @override Widget build(BuildContext context) { return Scaffold( body: _NAV_ITEMS[_currentIndex].child, body: _navItems[_currentIndex].child, bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, items: _NAV_ITEMS items: _navItems .map( (item) => BottomNavigationBarItem( label: item.label, Loading lib/common/widget/page_template.dart +13 −10 Original line number Diff line number Diff line Loading @@ -6,11 +6,13 @@ import 'package:stamped/common/util/shared_ui_constants.dart'; class PageTemplate extends StatelessWidget { final String title; final Widget child; final bool showLogout; const PageTemplate({ super.key, required this.title, required this.child, this.showLogout = false, }); @override Loading @@ -20,16 +22,17 @@ class PageTemplate extends StatelessWidget { title: Text(title), centerTitle: true, scrolledUnderElevation: 0.0, // TODO: remove when profile page with signing out is completed actions: [ actions: showLogout ? [ IconButton( onPressed: () async { await GoogleSignIn().signOut(); FirebaseAuth.instance.signOut(); }, icon: Icon(Icons.logout), ) ], ), ] : [], ), body: Padding( padding: const EdgeInsets.all(STANDARD_GAP), Loading lib/pages/profile/profile_page.dart 0 → 100644 +136 −0 Original line number Diff line number Diff line import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:stamped/common/util/shared_ui_constants.dart'; import 'package:stamped/common/widget/page_template.dart'; class ProfilePage extends StatefulWidget { ProfilePage({Key? key}) : super(key: key); @override State<ProfilePage> createState() => _ProfilePageState(); } class _ProfilePageState extends State<ProfilePage> { late final TextEditingController _textEditingController; var _currentUser = FirebaseAuth.instance.currentUser!; @override void initState() { super.initState(); _textEditingController = TextEditingController(); } @override void dispose() { _textEditingController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return PageTemplate( title: 'Profile', showLogout: true, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( height: 160, child: Stack( children: [ CircleAvatar( backgroundImage: NetworkImage(_currentUser.photoURL!), radius: 80, ), Positioned( right: 0, top: 0, child: Container( constraints: BoxConstraints( minWidth: 10, minHeight: 10, ), // TODO: add profile picture editing child: _buildEditButton(() {}), ), ) ], ), ), SizedBox( height: STANDARD_GAP, ), Row( mainAxisSize: MainAxisSize.min, children: [ Text( _currentUser.displayName!, style: TextStyle(fontSize: 20), ), SizedBox( width: STANDARD_GAP * 0.3, ), _buildEditButton( () async { final newDisplayName = await _showEditDisplayNameDialog(context); if (newDisplayName == null || newDisplayName.isEmpty) { return; } await _currentUser.updateDisplayName(newDisplayName); // TODO: take out the logic to a controller setState(() { _currentUser = FirebaseAuth.instance.currentUser!; }); }, ), ], ) ], ), ), ); } Widget _buildEditButton( VoidCallback onPressed, ) => CircleAvatar( backgroundColor: Colors.blue[100], child: IconButton( onPressed: onPressed, icon: Icon(Icons.edit), ), ); Future<String?> _showEditDisplayNameDialog(BuildContext context) => showDialog<String>( context: context, builder: (context) => AlertDialog( title: Text('Edit Display Name'), content: TextField( decoration: InputDecoration(hintText: 'Enter a new display name'), autofocus: true, controller: _textEditingController, ), actions: [ TextButton( onPressed: () { _submitDisplayName(); }, child: Text('Submit'), ), ], ), ); void _submitDisplayName() { Navigator.of(context).pop(_textEditingController.text); } } Loading
lib/bottom_nav_bar/widget/bottom_nav_bar.dart +5 −5 Original line number Diff line number Diff line Loading @@ -2,8 +2,9 @@ import 'package:flutter/material.dart'; import 'package:stamped/bottom_nav_bar/model/bottom_nav_bar_item.dart'; import 'package:stamped/pages/collections/collections_page.dart'; import 'package:stamped/pages/home/home_page.dart'; import 'package:stamped/pages/profile/profile_page.dart'; const List<BottomNavBarItem> _NAV_ITEMS = [ final List<BottomNavBarItem> _navItems = [ BottomNavBarItem( label: 'Home', icon: Icon(Icons.home), Loading @@ -29,8 +30,7 @@ const List<BottomNavBarItem> _NAV_ITEMS = [ BottomNavBarItem( label: 'Profile', icon: Icon(Icons.person), // TODO: replace with the profile page child: Placeholder(), child: ProfilePage(), ), ]; Loading @@ -47,10 +47,10 @@ class _BottomNavBarState extends State<BottomNavBar> { @override Widget build(BuildContext context) { return Scaffold( body: _NAV_ITEMS[_currentIndex].child, body: _navItems[_currentIndex].child, bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, items: _NAV_ITEMS items: _navItems .map( (item) => BottomNavigationBarItem( label: item.label, Loading
lib/common/widget/page_template.dart +13 −10 Original line number Diff line number Diff line Loading @@ -6,11 +6,13 @@ import 'package:stamped/common/util/shared_ui_constants.dart'; class PageTemplate extends StatelessWidget { final String title; final Widget child; final bool showLogout; const PageTemplate({ super.key, required this.title, required this.child, this.showLogout = false, }); @override Loading @@ -20,16 +22,17 @@ class PageTemplate extends StatelessWidget { title: Text(title), centerTitle: true, scrolledUnderElevation: 0.0, // TODO: remove when profile page with signing out is completed actions: [ actions: showLogout ? [ IconButton( onPressed: () async { await GoogleSignIn().signOut(); FirebaseAuth.instance.signOut(); }, icon: Icon(Icons.logout), ) ], ), ] : [], ), body: Padding( padding: const EdgeInsets.all(STANDARD_GAP), Loading
lib/pages/profile/profile_page.dart 0 → 100644 +136 −0 Original line number Diff line number Diff line import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:stamped/common/util/shared_ui_constants.dart'; import 'package:stamped/common/widget/page_template.dart'; class ProfilePage extends StatefulWidget { ProfilePage({Key? key}) : super(key: key); @override State<ProfilePage> createState() => _ProfilePageState(); } class _ProfilePageState extends State<ProfilePage> { late final TextEditingController _textEditingController; var _currentUser = FirebaseAuth.instance.currentUser!; @override void initState() { super.initState(); _textEditingController = TextEditingController(); } @override void dispose() { _textEditingController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return PageTemplate( title: 'Profile', showLogout: true, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( height: 160, child: Stack( children: [ CircleAvatar( backgroundImage: NetworkImage(_currentUser.photoURL!), radius: 80, ), Positioned( right: 0, top: 0, child: Container( constraints: BoxConstraints( minWidth: 10, minHeight: 10, ), // TODO: add profile picture editing child: _buildEditButton(() {}), ), ) ], ), ), SizedBox( height: STANDARD_GAP, ), Row( mainAxisSize: MainAxisSize.min, children: [ Text( _currentUser.displayName!, style: TextStyle(fontSize: 20), ), SizedBox( width: STANDARD_GAP * 0.3, ), _buildEditButton( () async { final newDisplayName = await _showEditDisplayNameDialog(context); if (newDisplayName == null || newDisplayName.isEmpty) { return; } await _currentUser.updateDisplayName(newDisplayName); // TODO: take out the logic to a controller setState(() { _currentUser = FirebaseAuth.instance.currentUser!; }); }, ), ], ) ], ), ), ); } Widget _buildEditButton( VoidCallback onPressed, ) => CircleAvatar( backgroundColor: Colors.blue[100], child: IconButton( onPressed: onPressed, icon: Icon(Icons.edit), ), ); Future<String?> _showEditDisplayNameDialog(BuildContext context) => showDialog<String>( context: context, builder: (context) => AlertDialog( title: Text('Edit Display Name'), content: TextField( decoration: InputDecoration(hintText: 'Enter a new display name'), autofocus: true, controller: _textEditingController, ), actions: [ TextButton( onPressed: () { _submitDisplayName(); }, child: Text('Submit'), ), ], ), ); void _submitDisplayName() { Navigator.of(context).pop(_textEditingController.text); } }