diff --git a/lib/routes.dart b/lib/routes.dart index 7c3d8ed90..74b1f4da8 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -47,31 +47,28 @@ final List routes = [ ), routes: [ GoRoute( - path: 'sales/order/:pk/pay', - name: 'sales-order-pay', - pageBuilder: (context, state) { - return CustomTransitionPage( - barrierColor: Colors.black54, - opaque: false, - transitionDuration: const Duration(milliseconds: 150), - transitionsBuilder: ( - context, - animation, - secondaryAnimation, - child, - ) { - return FadeTransition( - opacity: CurvedAnimation( - parent: animation, - curve: Curves.easeOut, - ), - child: child, - ); - }, - child: SalesOrderDialog(pk: state.params['pk']!), - ); - }, - ), + path: 'sales/order/:pk/pay', + name: 'sales-order-pay', + pageBuilder: (context, state) => CustomTransitionPage( + barrierColor: Colors.black54, + opaque: false, + transitionDuration: const Duration(milliseconds: 150), + transitionsBuilder: ( + context, + animation, + secondaryAnimation, + child, + ) { + return FadeTransition( + opacity: CurvedAnimation( + parent: animation, + curve: Curves.easeOut, + ), + child: child, + ); + }, + child: SalesOrderDialog(pk: state.params['pk']!), + )), ]), GoRoute( path: '/events', @@ -239,15 +236,13 @@ final List routes = [ GoRoute( path: '/pizzas', name: 'food', - pageBuilder: (context, state) { - return MaterialPage( - key: state.pageKey, - child: FoodScreen( - pk: (state.extra as Event?)?.foodEvent, - event: state.extra as Event?, - ), - ); - }, + pageBuilder: (context, state) => MaterialPage( + key: state.pageKey, + child: FoodScreen( + pk: (state.extra as Event?)?.foodEvent, + event: state.extra as Event?, + ), + ), routes: [ GoRoute( path: 'admin', diff --git a/lib/ui/screens/album_screen.dart b/lib/ui/screens/album_screen.dart index 3a3ca720a..1a543c8c6 100644 --- a/lib/ui/screens/album_screen.dart +++ b/lib/ui/screens/album_screen.dart @@ -141,20 +141,22 @@ class _AlbumScreenState extends State { ), ], ), - body: PhotoViewGallery.builder( - loadingBuilder: (_, __) => const Center( - child: CircularProgressIndicator(), - ), - backgroundDecoration: const BoxDecoration( - color: Colors.transparent, - ), - itemCount: album.photos.length, - builder: (context, i) => PhotoViewGalleryPageOptions( - imageProvider: NetworkImage(album.photos[i].full), - minScale: PhotoViewComputedScale.contained * 0.8, - maxScale: PhotoViewComputedScale.covered * 2, + body: SafeArea( + child: PhotoViewGallery.builder( + loadingBuilder: (_, __) => const Center( + child: CircularProgressIndicator(), + ), + backgroundDecoration: const BoxDecoration( + color: Colors.transparent, + ), + itemCount: album.photos.length, + builder: (context, i) => PhotoViewGalleryPageOptions( + imageProvider: NetworkImage(album.photos[i].full), + minScale: PhotoViewComputedScale.contained * 0.8, + maxScale: PhotoViewComputedScale.covered * 2, + ), + pageController: pageController, ), - pageController: pageController, ), ); }, diff --git a/lib/ui/screens/albums_screen.dart b/lib/ui/screens/albums_screen.dart index 9405f82d5..3fddeba0f 100644 --- a/lib/ui/screens/albums_screen.dart +++ b/lib/ui/screens/albums_screen.dart @@ -66,18 +66,20 @@ class _AlbumsScreenState extends State { onRefresh: () async { await _cubit.load(); }, - child: BlocBuilder( - builder: (context, listState) { - if (listState.hasException) { - return ErrorScrollView(listState.message!); - } else { - return AlbumListScrollView( - key: const PageStorageKey('albums'), - controller: _controller, - listState: listState, - ); - } - }, + child: SafeArea( + child: BlocBuilder( + builder: (context, listState) { + if (listState.hasException) { + return ErrorScrollView(listState.message!); + } else { + return AlbumListScrollView( + key: const PageStorageKey('albums'), + controller: _controller, + listState: listState, + ); + } + }, + ), ), ), ); diff --git a/lib/ui/screens/calendar_screen.dart b/lib/ui/screens/calendar_screen.dart index eec6f86a5..8f03608dd 100644 --- a/lib/ui/screens/calendar_screen.dart +++ b/lib/ui/screens/calendar_screen.dart @@ -73,18 +73,20 @@ class _CalendarScreenState extends State { onRefresh: () async { await _cubit.load(); }, - child: BlocBuilder( - builder: (context, calendarState) { - if (calendarState.hasException) { - return ErrorScrollView(calendarState.message!); - } else { - return CalendarScrollView( - key: const PageStorageKey('calendar'), - controller: _controller, - calendarState: calendarState, - ); - } - }, + child: SafeArea( + child: BlocBuilder( + builder: (context, calendarState) { + if (calendarState.hasException) { + return ErrorScrollView(calendarState.message!); + } else { + return CalendarScrollView( + key: const PageStorageKey('calendar'), + controller: _controller, + calendarState: calendarState, + ); + } + }, + ), ), ), ); diff --git a/lib/ui/screens/event_admin_screen.dart b/lib/ui/screens/event_admin_screen.dart index 9f8b3eff1..6caf8de8e 100644 --- a/lib/ui/screens/event_admin_screen.dart +++ b/lib/ui/screens/event_admin_screen.dart @@ -41,26 +41,28 @@ class _EventAdminScreenState extends State { context, ).loadRegistrations(); }, - child: BlocBuilder( - builder: (context, state) { - if (state.hasException) { - return ErrorScrollView(state.message!); - } else if (state.isLoading) { - return const Center(child: CircularProgressIndicator()); - } else { - return Scrollbar( - child: ListView.separated( - key: const PageStorageKey('event-admin'), - itemBuilder: (context, index) => _RegistrationTile( - registration: state.registrations[index], - requiresPayment: state.event!.paymentIsRequired, + child: SafeArea( + child: BlocBuilder( + builder: (context, state) { + if (state.hasException) { + return ErrorScrollView(state.message!); + } else if (state.isLoading) { + return const Center(child: CircularProgressIndicator()); + } else { + return Scrollbar( + child: ListView.separated( + key: const PageStorageKey('event-admin'), + itemBuilder: (context, index) => _RegistrationTile( + registration: state.registrations[index], + requiresPayment: state.event!.paymentIsRequired, + ), + separatorBuilder: (_, __) => const Divider(), + itemCount: state.registrations.length, ), - separatorBuilder: (_, __) => const Divider(), - itemCount: state.registrations.length, - ), - ); - } - }, + ); + } + }, + ), ), ), ); diff --git a/lib/ui/screens/event_screen.dart b/lib/ui/screens/event_screen.dart index b594ca7f1..1ca858a02 100644 --- a/lib/ui/screens/event_screen.dart +++ b/lib/ui/screens/event_screen.dart @@ -898,24 +898,23 @@ class _EventScreenState extends State { actions: [_makeShareEventButton(widget.pk)], ), body: RefreshIndicator( - onRefresh: () async { - // Await only the event info. - _registrationsCubit.load(); - await _eventCubit.load(); - }, - child: ErrorScrollView(state.message!), - ), + onRefresh: () async { + // Await only the event info. + _registrationsCubit.load(); + await _eventCubit.load(); + }, + child: SafeArea(child: ErrorScrollView(state.message!))), ); } else if (state.isLoading && widget.event == null && state.result == null) { return Scaffold( - appBar: ThaliaAppBar( - title: const Text('EVENT'), - actions: [_makeShareEventButton(widget.pk)], - ), - body: const Center(child: CircularProgressIndicator()), - ); + appBar: ThaliaAppBar( + title: const Text('EVENT'), + actions: [_makeShareEventButton(widget.pk)], + ), + body: const SafeArea( + child: Center(child: CircularProgressIndicator()))); } else { final event = (state.result ?? widget.event)!; return Scaffold( @@ -941,46 +940,48 @@ class _EventScreenState extends State { _registrationsCubit.load(); await _eventCubit.load(); }, - child: BlocBuilder( - bloc: _registrationsCubit, - builder: (context, listState) { - return Scrollbar( - controller: _controller, - child: CustomScrollView( + child: SafeArea( + child: BlocBuilder( + bloc: _registrationsCubit, + builder: (context, listState) { + return Scrollbar( controller: _controller, - key: const PageStorageKey('event'), - slivers: [ - SliverToBoxAdapter( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _makeMap(event), - const Divider(height: 0), - _makeEventInfo(event), - const Divider(), - _makeDescription(event), - ], + child: CustomScrollView( + controller: _controller, + key: const PageStorageKey('event'), + slivers: [ + SliverToBoxAdapter( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _makeMap(event), + const Divider(height: 0), + _makeEventInfo(event), + const Divider(), + _makeDescription(event), + ], + ), ), - ), - if (event.registrationIsOptional || - event.registrationIsRequired) ...[ - const SliverToBoxAdapter(child: Divider()), - _makeRegistrationsHeader(listState), - _makeRegistrations(listState), - if (listState.isLoadingMore) - const SliverPadding( - padding: EdgeInsets.all(8), - sliver: SliverList( - delegate: SliverChildListDelegate.fixed([ - Center(child: CircularProgressIndicator()), - ]), + if (event.registrationIsOptional || + event.registrationIsRequired) ...[ + const SliverToBoxAdapter(child: Divider()), + _makeRegistrationsHeader(listState), + _makeRegistrations(listState), + if (listState.isLoadingMore) + const SliverPadding( + padding: EdgeInsets.all(8), + sliver: SliverList( + delegate: SliverChildListDelegate.fixed([ + Center(child: CircularProgressIndicator()), + ]), + ), ), - ), + ], ], - ], - ), - ); - }, + ), + ); + }, + ), ), ), ); diff --git a/lib/ui/screens/food_admin_screen.dart b/lib/ui/screens/food_admin_screen.dart index f0e72ff69..a1a45bfc9 100644 --- a/lib/ui/screens/food_admin_screen.dart +++ b/lib/ui/screens/food_admin_screen.dart @@ -60,24 +60,26 @@ class _FoodAdminScreenState extends State { onRefresh: () async { await BlocProvider.of(context).load(); }, - child: BlocBuilder( - builder: (context, state) { - if (state.hasException) { - return ErrorScrollView(state.message!); - } else if (state.isLoading) { - return const Center(child: CircularProgressIndicator()); - } else { - return Scrollbar( - child: ListView.separated( - key: const PageStorageKey('food-admin'), - itemBuilder: (context, index) => _OrderTile( - order: state.result![index], - ), - separatorBuilder: (_, __) => const Divider(), - itemCount: state.result!.length, - )); - } - }, + child: SafeArea( + child: BlocBuilder( + builder: (context, state) { + if (state.hasException) { + return ErrorScrollView(state.message!); + } else if (state.isLoading) { + return const Center(child: CircularProgressIndicator()); + } else { + return Scrollbar( + child: ListView.separated( + key: const PageStorageKey('food-admin'), + itemBuilder: (context, index) => _OrderTile( + order: state.result![index], + ), + separatorBuilder: (_, __) => const Divider(), + itemCount: state.result!.length, + )); + } + }, + ), ), ), ); diff --git a/lib/ui/screens/food_screen.dart b/lib/ui/screens/food_screen.dart index be545b88c..ca6f1b183 100644 --- a/lib/ui/screens/food_screen.dart +++ b/lib/ui/screens/food_screen.dart @@ -349,27 +349,29 @@ class _FoodScreenState extends State { ), body: RefreshIndicator( onRefresh: () => _foodCubit.load(), - child: ListView( - key: const PageStorageKey('food'), - controller: _controller, - physics: const AlwaysScrollableScrollPhysics(), - padding: const EdgeInsets.all(16), - children: [ - _makeEventInfo(foodEvent), - _makeOrderInfo(foodEvent), - const Divider(), - Card( - child: Column( - children: ListTile.divideTiles( - context: context, - tiles: [ - for (final product in products!) - _ProductTile(product) - ], - ).toList(), + child: SafeArea( + child: ListView( + key: const PageStorageKey('food'), + controller: _controller, + physics: const AlwaysScrollableScrollPhysics(), + padding: const EdgeInsets.all(16), + children: [ + _makeEventInfo(foodEvent), + _makeOrderInfo(foodEvent), + const Divider(), + Card( + child: Column( + children: ListTile.divideTiles( + context: context, + tiles: [ + for (final product in products!) + _ProductTile(product) + ], + ).toList(), + ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/ui/screens/login_screen.dart b/lib/ui/screens/login_screen.dart index efe7a202b..dfab53680 100644 --- a/lib/ui/screens/login_screen.dart +++ b/lib/ui/screens/login_screen.dart @@ -29,59 +29,63 @@ class _LoginScreenState extends State { builder: (context, authState) { if (authState is LoadingAuthState) { return Scaffold( - backgroundColor: const Color(0xFFE62272), - body: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Center( - child: Image( - image: logo, - width: 260, - ), - ), - const SizedBox(height: 50), - const SizedBox( - height: 50, - child: Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xFFE62272), + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: Image( + image: logo, + width: 260, + ), ), - ), + const SizedBox(height: 50), + const SizedBox( + height: 50, + child: Center( + child: CircularProgressIndicator( + valueColor: + AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + ], ), - ], - ), - ); + )); } else { return Scaffold( backgroundColor: magenta, - body: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Center( - child: Image( - image: logo, - width: 260, + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center( + child: Image( + image: logo, + width: 260, + ), ), - ), - const SizedBox(height: 50), - SizedBox( - height: 50, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black87, - foregroundColor: Colors.white, + const SizedBox(height: 50), + SizedBox( + height: 50, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black87, + foregroundColor: Colors.white, + ), + onPressed: () { + BlocProvider.of( + context, + listen: false, + ).logIn(); + }, + child: const Text('LOGIN'), ), - onPressed: () { - BlocProvider.of( - context, - listen: false, - ).logIn(); - }, - child: const Text('LOGIN'), ), - ), - ], + ], + ), ), ); } diff --git a/lib/ui/screens/members_screen.dart b/lib/ui/screens/members_screen.dart index 867c1eb68..e05edbc84 100644 --- a/lib/ui/screens/members_screen.dart +++ b/lib/ui/screens/members_screen.dart @@ -66,18 +66,20 @@ class _MembersScreenState extends State { onRefresh: () async { await _cubit.load(); }, - child: BlocBuilder( - builder: (context, listState) { - if (listState.hasException) { - return ErrorScrollView(listState.message!); - } else { - return MemberListScrollView( - key: const PageStorageKey('members'), - controller: _controller, - listState: listState, - ); - } - }, + child: SafeArea( + child: BlocBuilder( + builder: (context, listState) { + if (listState.hasException) { + return ErrorScrollView(listState.message!); + } else { + return MemberListScrollView( + key: const PageStorageKey('members'), + controller: _controller, + listState: listState, + ); + } + }, + ), ), ), ); diff --git a/lib/ui/screens/profile_screen.dart b/lib/ui/screens/profile_screen.dart index 7bb5f8a79..428d811db 100644 --- a/lib/ui/screens/profile_screen.dart +++ b/lib/ui/screens/profile_screen.dart @@ -458,54 +458,56 @@ class _ProfileScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: BlocBuilder( - bloc: _memberCubit, - builder: (context, state) { - if (state.hasException) { - return CustomScrollView( - controller: _scrollController, - slivers: [ - _makeAppBar(), - SliverFillRemaining( - child: ErrorCenter(state.message!), - ), - ], - ); - } else if (state.isLoading && widget.member == null) { - return CustomScrollView( - controller: _scrollController, - slivers: [ - _makeAppBar(), - const SliverFillRemaining( - child: Center(child: CircularProgressIndicator()), - ), - ], - ); - } else { - return CustomScrollView( - key: const PageStorageKey('profile'), - controller: _scrollController, - slivers: [ - _makeAppBar((state.result ?? widget.member)!), - _makeFactsSliver((state.result ?? widget.member)!), - if (!state.isLoading) ...[ - if (state.result!.achievements.isNotEmpty) - _makeAchievementsSliver(state.result!), - if (state.result!.societies.isNotEmpty) - _makeSocietiesSliver(state.result!), - ] else ...[ - const SliverPadding( - padding: EdgeInsets.all(16), - sliver: SliverToBoxAdapter( - child: Center(child: CircularProgressIndicator()), - ), + body: SafeArea( + child: BlocBuilder( + bloc: _memberCubit, + builder: (context, state) { + if (state.hasException) { + return CustomScrollView( + controller: _scrollController, + slivers: [ + _makeAppBar(), + SliverFillRemaining( + child: ErrorCenter(state.message!), ), ], - const SliverToBoxAdapter(child: SizedBox(height: 32)) - ], - ); - } - }, + ); + } else if (state.isLoading && widget.member == null) { + return CustomScrollView( + controller: _scrollController, + slivers: [ + _makeAppBar(), + const SliverFillRemaining( + child: Center(child: CircularProgressIndicator()), + ), + ], + ); + } else { + return CustomScrollView( + key: const PageStorageKey('profile'), + controller: _scrollController, + slivers: [ + _makeAppBar((state.result ?? widget.member)!), + _makeFactsSliver((state.result ?? widget.member)!), + if (!state.isLoading) ...[ + if (state.result!.achievements.isNotEmpty) + _makeAchievementsSliver(state.result!), + if (state.result!.societies.isNotEmpty) + _makeSocietiesSliver(state.result!), + ] else ...[ + const SliverPadding( + padding: EdgeInsets.all(16), + sliver: SliverToBoxAdapter( + child: Center(child: CircularProgressIndicator()), + ), + ), + ], + const SliverToBoxAdapter(child: SizedBox(height: 32)) + ], + ); + } + }, + ), ), ); } diff --git a/lib/ui/screens/registration_screen.dart b/lib/ui/screens/registration_screen.dart index a68f81914..d8929a637 100644 --- a/lib/ui/screens/registration_screen.dart +++ b/lib/ui/screens/registration_screen.dart @@ -42,193 +42,195 @@ class _RegistrationScreenState extends State { @override Widget build(BuildContext context) { - return BlocBuilder( - bloc: _registrationFieldsCubit, - builder: (context, state) { - if (state.hasException) { - return Scaffold( - appBar: ThaliaAppBar( - title: const Text('REGISTRATION'), - leading: const CloseButton(), - ), - body: ErrorCenter(state.message!), - ); - } else if (state.isLoading) { + return SafeArea( + child: BlocBuilder( + bloc: _registrationFieldsCubit, + builder: (context, state) { + if (state.hasException) { + return Scaffold( + appBar: ThaliaAppBar( + title: const Text('REGISTRATION'), + leading: const CloseButton(), + ), + body: ErrorCenter(state.message!), + ); + } else if (state.isLoading) { + return Scaffold( + appBar: ThaliaAppBar( + title: const Text('REGISTRATION'), + leading: const CloseButton(), + ), + body: const Center(child: CircularProgressIndicator()), + ); + } else {} return Scaffold( appBar: ThaliaAppBar( title: const Text('REGISTRATION'), leading: const CloseButton(), ), - body: const Center(child: CircularProgressIndicator()), - ); - } else {} - return Scaffold( - appBar: ThaliaAppBar( - title: const Text('REGISTRATION'), - leading: const CloseButton(), - ), - body: SingleChildScrollView( - child: Form( - key: _formKey, - child: Column( - children: [ - ...state.result!.entries.map((entry) { - final field = entry.value; - if (field is TextRegistrationField) { - return Column( - children: [ - ListTile( - title: Text(field.label), - subtitle: field.description.isNotEmpty - ? Text(field.description) - : null, - ), - Padding( - padding: const EdgeInsets.only( - left: 16, - bottom: 16, - right: 16, + body: SingleChildScrollView( + child: Form( + key: _formKey, + child: Column( + children: [ + ...state.result!.entries.map((entry) { + final field = entry.value; + if (field is TextRegistrationField) { + return Column( + children: [ + ListTile( + title: Text(field.label), + subtitle: field.description.isNotEmpty + ? Text(field.description) + : null, ), - child: TextFormField( - initialValue: field.value, - minLines: 1, - maxLines: 5, - decoration: InputDecoration( - labelText: field.isRequired - ? '${field.label} *' - : field.label, - hintText: 'Lorem ipsum...', + Padding( + padding: const EdgeInsets.only( + left: 16, + bottom: 16, + right: 16, + ), + child: TextFormField( + initialValue: field.value, + minLines: 1, + maxLines: 5, + decoration: InputDecoration( + labelText: field.isRequired + ? '${field.label} *' + : field.label, + hintText: 'Lorem ipsum...', + ), + validator: (value) { + if (field.isRequired && + (value == null || value.isEmpty)) { + return 'Please fill in this field.'; + } + return null; + }, + onSaved: (newValue) => field.value = newValue, ), - validator: (value) { - if (field.isRequired && - (value == null || value.isEmpty)) { - return 'Please fill in this field.'; - } - return null; - }, - onSaved: (newValue) => field.value = newValue, ), - ), - ], - ); - } else if (field is IntegerRegistrationField) { - return Column( - children: [ - ListTile( - dense: field.description.isEmpty, + ], + ); + } else if (field is IntegerRegistrationField) { + return Column( + children: [ + ListTile( + dense: field.description.isEmpty, + title: Text(field.label), + subtitle: field.description.isNotEmpty + ? Text(field.description) + : null, + ), + Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 16, + ), + child: TextFormField( + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + decoration: InputDecoration( + labelText: field.isRequired + ? '${field.label} *' + : field.label, + hintText: '123...', + ), + initialValue: field.value?.toString(), + validator: (value) { + if (field.isRequired && + (value == null || value.isEmpty)) { + return 'Please fill in this field.'; + } + return null; + }, + onSaved: (newValue) => + field.value = int.tryParse(newValue!), + ), + ), + ], + ); + } else if (field is CheckboxRegistrationField) { + return Padding( + padding: const EdgeInsets.only(bottom: 16), + child: _CheckboxFormField( + initialValue: field.value ?? false, + onSaved: (newValue) => field.value = newValue, title: Text(field.label), subtitle: field.description.isNotEmpty ? Text(field.description) : null, ), - Padding( - padding: const EdgeInsets.only( - left: 16, - right: 16, - bottom: 16, - ), - child: TextFormField( - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: InputDecoration( - labelText: field.isRequired - ? '${field.label} *' - : field.label, - hintText: '123...', - ), - initialValue: field.value?.toString(), - validator: (value) { - if (field.isRequired && - (value == null || value.isEmpty)) { - return 'Please fill in this field.'; - } - return null; - }, - onSaved: (newValue) => - field.value = int.tryParse(newValue!), - ), + ); + } else { + return const SizedBox(height: 0); + } + }), + Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton.icon( + onPressed: () { + _formKey.currentState!.reset(); + }, + icon: const Icon(Icons.restore_page_outlined), + label: const Text('RESTORE'), ), - ], - ); - } else if (field is CheckboxRegistrationField) { - return Padding( - padding: const EdgeInsets.only(bottom: 16), - child: _CheckboxFormField( - initialValue: field.value ?? false, - onSaved: (newValue) => field.value = newValue, - title: Text(field.label), - subtitle: field.description.isNotEmpty - ? Text(field.description) - : null, - ), - ); - } else { - return const SizedBox(height: 0); - } - }), - Padding( - padding: const EdgeInsets.all(16), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton.icon( - onPressed: () { - _formKey.currentState!.reset(); - }, - icon: const Icon(Icons.restore_page_outlined), - label: const Text('RESTORE'), - ), - const SizedBox(width: 16), - ElevatedButton.icon( - onPressed: () async { - if (_formKey.currentState!.validate()) { - _formKey.currentState!.save(); + const SizedBox(width: 16), + ElevatedButton.icon( + onPressed: () async { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); - final messenger = ScaffoldMessenger.of(context); + final messenger = ScaffoldMessenger.of(context); - try { - await _registrationFieldsCubit.update( - eventPk: widget.eventPk, - registrationPk: widget.registrationPk, - fields: state.result!, - ); + try { + await _registrationFieldsCubit.update( + eventPk: widget.eventPk, + registrationPk: widget.registrationPk, + fields: state.result!, + ); - if (mounted) Navigator.of(context).pop(); + if (mounted) Navigator.of(context).pop(); - messenger.showSnackBar( - const SnackBar( - behavior: SnackBarBehavior.floating, - content: Text( - 'Your registration has been updated.', + messenger.showSnackBar( + const SnackBar( + behavior: SnackBarBehavior.floating, + content: Text( + 'Your registration has been updated.', + ), ), - ), - ); - } on ApiException { - messenger.showSnackBar( - const SnackBar( - behavior: SnackBarBehavior.floating, - content: Text( - 'Could not update your registration.', + ); + } on ApiException { + messenger.showSnackBar( + const SnackBar( + behavior: SnackBarBehavior.floating, + content: Text( + 'Could not update your registration.', + ), ), - ), - ); + ); + } } - } - }, - icon: const Icon(Icons.check), - label: const Text('SUBMIT'), - ), - ], + }, + icon: const Icon(Icons.check), + label: const Text('SUBMIT'), + ), + ], + ), ), - ), - ], + ], + ), ), ), - ), - ); - }, + ); + }, + ), ); } } diff --git a/lib/ui/screens/settings_screen.dart b/lib/ui/screens/settings_screen.dart index 13dbb6133..8d03bd74f 100644 --- a/lib/ui/screens/settings_screen.dart +++ b/lib/ui/screens/settings_screen.dart @@ -14,101 +14,103 @@ class SettingsScreen extends StatelessWidget { return Scaffold( appBar: ThaliaAppBar(title: const Text('SETTINGS')), drawer: MenuDrawer(), - body: BlocBuilder( - builder: (context, state) { - if (state.hasException) { - return RefreshIndicator( - onRefresh: () => BlocProvider.of(context).load(), - child: ListView( + body: SafeArea( + child: BlocBuilder( + builder: (context, state) { + if (state.hasException) { + return RefreshIndicator( + onRefresh: () => BlocProvider.of(context).load(), + child: ListView( + padding: const EdgeInsets.all(16), + children: [ + Text('THEME', style: textTheme.caption), + const _ThemeModeCard(), + const SizedBox(height: 8), + Text('NOTIFICATIONS', style: textTheme.caption), + Center(child: Text(state.message!)), + const SizedBox(height: 8), + Text('ABOUT', style: textTheme.caption), + const _AboutCard(), + ], + ), + ); + } else if (state.isLoading && state.categories == null) { + return ListView( padding: const EdgeInsets.all(16), children: [ Text('THEME', style: textTheme.caption), const _ThemeModeCard(), const SizedBox(height: 8), Text('NOTIFICATIONS', style: textTheme.caption), - Center(child: Text(state.message!)), + const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Center(child: CircularProgressIndicator()), + ), const SizedBox(height: 8), Text('ABOUT', style: textTheme.caption), const _AboutCard(), ], - ), - ); - } else if (state.isLoading && state.categories == null) { - return ListView( - padding: const EdgeInsets.all(16), - children: [ - Text('THEME', style: textTheme.caption), - const _ThemeModeCard(), - const SizedBox(height: 8), - Text('NOTIFICATIONS', style: textTheme.caption), - const Padding( - padding: EdgeInsets.symmetric(vertical: 16), - child: Center(child: CircularProgressIndicator()), - ), - const SizedBox(height: 8), - Text('ABOUT', style: textTheme.caption), - const _AboutCard(), - ], - ); - } else { - return ListView( - padding: const EdgeInsets.all(16), - children: [ - Text('THEME', style: textTheme.caption), - const _ThemeModeCard(), - const SizedBox(height: 8), - Text('NOTIFICATIONS', style: textTheme.caption), - if (!state.hasPermissions!) ...[ + ); + } else { + return ListView( + padding: const EdgeInsets.all(16), + children: [ + Text('THEME', style: textTheme.caption), + const _ThemeModeCard(), + const SizedBox(height: 8), + Text('NOTIFICATIONS', style: textTheme.caption), + if (!state.hasPermissions!) ...[ + Card( + margin: const EdgeInsets.symmetric(vertical: 8), + child: Padding( + padding: const EdgeInsets.all(4), + child: Row( + children: [ + const Padding( + padding: EdgeInsets.all(12), + child: Icon(Icons.notifications_off_outlined), + ), + Expanded( + child: Text( + 'Notifications are disabled. Enable ' + 'them in your device settings.', + style: textTheme.bodyText2!.copyWith( + color: textTheme.caption!.color, + ), + ), + ), + ], + ), + ), + ), + ], Card( margin: const EdgeInsets.symmetric(vertical: 8), - child: Padding( - padding: const EdgeInsets.all(4), - child: Row( - children: [ - const Padding( - padding: EdgeInsets.all(12), - child: Icon(Icons.notifications_off_outlined), - ), - Expanded( - child: Text( - 'Notifications are disabled. Enable ' - 'them in your device settings.', - style: textTheme.bodyText2!.copyWith( - color: textTheme.caption!.color, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: ListTile.divideTiles( + context: context, + tiles: [ + for (final category in state.categories!) + _NotificationSettingTile( + category: category, + enabled: state.device!.receiveCategory.contains( + category.key, ), ), - ), ], - ), + ).toList(), ), ), + const SizedBox(height: 8), + Text('ABOUT', style: textTheme.caption), + const _AboutCard(), ], - Card( - margin: const EdgeInsets.symmetric(vertical: 8), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: ListTile.divideTiles( - context: context, - tiles: [ - for (final category in state.categories!) - _NotificationSettingTile( - category: category, - enabled: state.device!.receiveCategory.contains( - category.key, - ), - ), - ], - ).toList(), - ), - ), - const SizedBox(height: 8), - Text('ABOUT', style: textTheme.caption), - const _AboutCard(), - ], - ); - } - }, + ); + } + }, + ), ), ); } diff --git a/lib/ui/screens/welcome_screen.dart b/lib/ui/screens/welcome_screen.dart index 9f83342db..1a6fa52e1 100644 --- a/lib/ui/screens/welcome_screen.dart +++ b/lib/ui/screens/welcome_screen.dart @@ -165,34 +165,36 @@ class _WelcomeScreenState extends State { return Scaffold( appBar: ThaliaAppBar(title: const Text('WELCOME')), drawer: MenuDrawer(), - body: RefreshIndicator( - onRefresh: () => BlocProvider.of(context).load(), - child: BlocBuilder( - builder: (context, state) { - if (state.hasException) { - return ErrorScrollView(state.message!); - } else if (!state.hasResults) { - return const Center(child: CircularProgressIndicator()); - } else { - return Scrollbar( - child: ListView( - key: const PageStorageKey('welcome'), - physics: const AlwaysScrollableScrollPhysics(), - children: [ - _makeSlides(state.slides!), - if (state.slides!.isNotEmpty) const Divider(height: 0), - _makeArticles(state.articles!), - if (state.articles!.isNotEmpty) - const Divider(indent: 16, endIndent: 16, height: 8), - _makeUpcomingEvents(state.upcomingEvents!), - TextButton( - onPressed: () => context.goNamed('calendar'), - child: const Text('SHOW THE ENTIRE AGENDA'), - ), - ], - )); - } - }, + body: SafeArea( + child: RefreshIndicator( + onRefresh: () => BlocProvider.of(context).load(), + child: BlocBuilder( + builder: (context, state) { + if (state.hasException) { + return ErrorScrollView(state.message!); + } else if (!state.hasResults) { + return const Center(child: CircularProgressIndicator()); + } else { + return Scrollbar( + child: ListView( + key: const PageStorageKey('welcome'), + physics: const AlwaysScrollableScrollPhysics(), + children: [ + _makeSlides(state.slides!), + if (state.slides!.isNotEmpty) const Divider(height: 0), + _makeArticles(state.articles!), + if (state.articles!.isNotEmpty) + const Divider(indent: 16, endIndent: 16, height: 8), + _makeUpcomingEvents(state.upcomingEvents!), + TextButton( + onPressed: () => context.goNamed('calendar'), + child: const Text('SHOW THE ENTIRE AGENDA'), + ), + ], + )); + } + }, + ), ), ), );