Added keyboard checks

This commit is contained in:
2025-08-17 20:59:21 +02:00
parent 932e372589
commit 360ee839f8

View File

@@ -77,249 +77,260 @@ class _CreateGameViewState extends State<CreateGameView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CupertinoPageScaffold( return PopScope(
resizeToAvoidBottomInset: false, canPop: false,
navigationBar: CupertinoNavigationBar( onPopInvokedWithResult: (bool didPop, dynamic result) async {
previousPageTitle: AppLocalizations.of(context).games, if (!didPop) {
middle: Text(AppLocalizations.of(context).new_game), await _keyboardDelay();
), if (context.mounted) Navigator.pop(context);
child: SafeArea( }
child: SingleChildScrollView( },
child: Column( child: CupertinoPageScaffold(
mainAxisAlignment: MainAxisAlignment.start, resizeToAvoidBottomInset: false,
crossAxisAlignment: CrossAxisAlignment.start, navigationBar: CupertinoNavigationBar(
children: [ previousPageTitle: AppLocalizations.of(context).games,
Padding( middle: Text(AppLocalizations.of(context).new_game),
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), ),
child: Text( child: SafeArea(
AppLocalizations.of(context).game, child: SingleChildScrollView(
style: CustomTheme.rowTitle, child: Column(
), mainAxisAlignment: MainAxisAlignment.start,
), crossAxisAlignment: CrossAxisAlignment.start,
Padding( children: [
padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), Padding(
child: CupertinoTextField( padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
decoration: const BoxDecoration(), child: Text(
maxLength: 20, AppLocalizations.of(context).game,
prefix: Text(AppLocalizations.of(context).name), style: CustomTheme.rowTitle,
textAlign: TextAlign.right, ),
placeholder: AppLocalizations.of(context).game_title,
controller: _gameTitleTextController,
onSubmitted: (_) {
_playerNameFocusNodes.isNotEmpty
? _playerNameFocusNodes[0].requestFocus()
: FocusScope.of(context).unfocus();
},
textInputAction: _playerNameFocusNodes.isNotEmpty
? TextInputAction.next
: TextInputAction.done,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(15, 10, 10, 0),
child: CupertinoTextField(
decoration: const BoxDecoration(),
readOnly: true,
prefix: Text(AppLocalizations.of(context).mode),
suffix: Row(
children: [
_getDisplayedGameMode(),
const SizedBox(width: 3),
const CupertinoListTileChevron(),
],
), ),
onTap: () async { Padding(
final selectedMode = await Navigator.push( padding: const EdgeInsets.fromLTRB(15, 10, 10, 0),
context, child: CupertinoTextField(
CupertinoPageRoute( decoration: const BoxDecoration(),
builder: (context) => ModeSelectionMenu( maxLength: 20,
pointLimit: ConfigService.getPointLimit(), prefix: Text(AppLocalizations.of(context).name),
showDeselection: false, textAlign: TextAlign.right,
), placeholder: AppLocalizations.of(context).game_title,
), controller: _gameTitleTextController,
); onSubmitted: (_) {
_playerNameFocusNodes.isNotEmpty
setState(() { ? _playerNameFocusNodes[0].requestFocus()
gameMode = selectedMode ?? gameMode; : FocusScope.of(context).unfocus();
}); },
}, textInputAction: _playerNameFocusNodes.isNotEmpty
), ? TextInputAction.next
), : TextInputAction.done,
Padding( ),
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), ),
child: Text( Padding(
AppLocalizations.of(context).players, padding: const EdgeInsets.fromLTRB(15, 10, 10, 0),
style: CustomTheme.rowTitle, child: CupertinoTextField(
), decoration: const BoxDecoration(),
), readOnly: true,
ReorderableListView.builder( prefix: Text(AppLocalizations.of(context).mode),
shrinkWrap: true, suffix: Row(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(8),
itemCount: _playerNameTextControllers.length,
onReorder: (oldIndex, newIndex) {
setState(() {
if (oldIndex < _playerNameTextControllers.length &&
newIndex <= _playerNameTextControllers.length) {
if (newIndex > oldIndex) newIndex--;
final item =
_playerNameTextControllers.removeAt(oldIndex);
_playerNameTextControllers.insert(newIndex, item);
}
});
},
itemBuilder: (context, index) {
return Padding(
key: ValueKey(index),
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [ children: [
CupertinoButton( _getDisplayedGameMode(),
padding: EdgeInsets.zero, const SizedBox(width: 3),
child: Icon( const CupertinoListTileChevron(),
CupertinoIcons.minus_circle_fill,
color: CustomTheme.red,
size: 25,
),
onPressed: () {
setState(() {
_playerNameTextControllers[index].dispose();
_playerNameTextControllers.removeAt(index);
});
},
),
Expanded(
child: CupertinoTextField(
controller: _playerNameTextControllers[index],
focusNode: _playerNameFocusNodes[index],
maxLength: 12,
placeholder:
'${AppLocalizations.of(context).player} ${index + 1}',
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(),
textInputAction:
index + 1 < _playerNameTextControllers.length
? TextInputAction.next
: TextInputAction.done,
onSubmitted: (_) {
if (index + 1 < _playerNameFocusNodes.length) {
_playerNameFocusNodes[index + 1]
.requestFocus();
} else {
FocusScope.of(context).unfocus();
}
},
),
),
AnimatedOpacity(
opacity: _playerNameTextControllers.length > 1
? 1.0
: 0.0,
duration: const Duration(
milliseconds: Constants.kFadeInDuration),
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: ReorderableDragStartListener(
index: index,
child: const Icon(
CupertinoIcons.line_horizontal_3,
color: CupertinoColors.systemGrey,
),
),
),
)
], ],
), ),
); onTap: () async {
}), await _keyboardDelay();
Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), if (context.mounted) {
child: Stack( final selectedMode = await Navigator.push(
children: [ context,
Row( CupertinoPageRoute(
mainAxisAlignment: MainAxisAlignment.start, builder: (context) => ModeSelectionMenu(
children: [ pointLimit: ConfigService.getPointLimit(),
CupertinoButton( showDeselection: false,
padding: EdgeInsets.zero, ),
onPressed: null, ),
child: Icon( );
CupertinoIcons.plus_circle_fill,
color: CustomTheme.primaryColor, setState(() {
size: 25, gameMode = selectedMode ?? gameMode;
), });
), }
], },
), ),
Center( ),
child: CupertinoButton( Padding(
padding: const EdgeInsets.symmetric(horizontal: 0), padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
child: Row( child: Text(
AppLocalizations.of(context).players,
style: CustomTheme.rowTitle,
),
),
ReorderableListView.builder(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(8),
itemCount: _playerNameTextControllers.length,
onReorder: (oldIndex, newIndex) {
setState(() {
if (oldIndex < _playerNameTextControllers.length &&
newIndex <= _playerNameTextControllers.length) {
if (newIndex > oldIndex) newIndex--;
final item =
_playerNameTextControllers.removeAt(oldIndex);
_playerNameTextControllers.insert(newIndex, item);
}
});
},
itemBuilder: (context, index) {
return Padding(
key: ValueKey(index),
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
CupertinoButton(
padding: EdgeInsets.zero,
child: Icon(
CupertinoIcons.minus_circle_fill,
color: CustomTheme.red,
size: 25,
),
onPressed: () {
setState(() {
_playerNameTextControllers[index].dispose();
_playerNameTextControllers.removeAt(index);
});
},
),
Expanded(
child: CupertinoTextField(
controller: _playerNameTextControllers[index],
focusNode: _playerNameFocusNodes[index],
maxLength: 12,
placeholder:
'${AppLocalizations.of(context).player} ${index + 1}',
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(),
textInputAction: index + 1 <
_playerNameTextControllers.length
? TextInputAction.next
: TextInputAction.done,
onSubmitted: (_) {
if (index + 1 <
_playerNameFocusNodes.length) {
_playerNameFocusNodes[index + 1]
.requestFocus();
} else {
FocusScope.of(context).unfocus();
}
},
),
),
AnimatedOpacity(
opacity: _playerNameTextControllers.length > 1
? 1.0
: 0.0,
duration: const Duration(
milliseconds: Constants.kFadeInDuration),
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: ReorderableDragStartListener(
index: index,
child: const Icon(
CupertinoIcons.line_horizontal_3,
color: CupertinoColors.systemGrey,
),
),
),
)
],
),
);
}),
Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 50),
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Expanded( CupertinoButton(
child: Center( padding: EdgeInsets.zero,
child: Text( onPressed: null,
AppLocalizations.of(context).add_player, child: Icon(
style: TextStyle( CupertinoIcons.plus_circle_fill,
color: CustomTheme.primaryColor), color: CustomTheme.primaryColor,
), size: 25,
), ),
), ),
], ],
), ),
onPressed: () { Center(
if (_playerNameTextControllers.length < maxPlayers) { child: CupertinoButton(
setState(() { padding: const EdgeInsets.symmetric(horizontal: 0),
_playerNameTextControllers child: Row(
.add(TextEditingController()); mainAxisAlignment: MainAxisAlignment.start,
_playerNameFocusNodes.add(FocusNode()); children: [
}); Expanded(
WidgetsBinding.instance.addPostFrameCallback((_) { child: Center(
_playerNameFocusNodes.last.requestFocus(); child: Text(
}); AppLocalizations.of(context).add_player,
} else { style: TextStyle(
_showFeedbackDialog(CreateStatus.maxPlayers); color: CustomTheme.primaryColor),
} ),
),
),
],
),
onPressed: () {
if (_playerNameTextControllers.length <
maxPlayers) {
setState(() {
_playerNameTextControllers
.add(TextEditingController());
_playerNameFocusNodes.add(FocusNode());
});
WidgetsBinding.instance
.addPostFrameCallback((_) {
_playerNameFocusNodes.last.requestFocus();
});
} else {
_showFeedbackDialog(CreateStatus.maxPlayers);
}
},
),
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 50),
child: Center(
child: CustomButton(
child: Text(
AppLocalizations.of(context).create_game,
style: TextStyle(
color: CustomTheme.primaryColor,
),
),
onPressed: () async {
await _keyboardDelay();
_checkAllGameAttributes();
}, },
), ),
), ),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 50),
child: Center(
child: CustomButton(
child: Text(
AppLocalizations.of(context).create_game,
style: TextStyle(
color: CustomTheme.primaryColor,
),
),
onPressed: () {
FocusScope.of(context).unfocus();
Future.delayed(
const Duration(
milliseconds: Constants.kKeyboardDelay), () {
_checkAllGameAttributes();
});
},
), ),
), KeyboardVisibilityBuilder(builder: (context, visible) {
if (visible) {
return SizedBox(
height: MediaQuery.of(context).viewInsets.bottom *
keyboardHeightAdjustmentFactor,
);
} else {
return const SizedBox.shrink();
}
})
],
), ),
KeyboardVisibilityBuilder(builder: (context, visible) { ))));
if (visible) {
return SizedBox(
height: MediaQuery.of(context).viewInsets.bottom *
keyboardHeightAdjustmentFactor,
);
} else {
return const SizedBox.shrink();
}
})
],
),
)));
} }
/// Returns a widget that displays the currently selected game mode in the View. /// Returns a widget that displays the currently selected game mode in the View.
@@ -460,8 +471,18 @@ class _CreateGameViewState extends State<CreateGameView> {
); );
} }
Future<void> _keyboardDelay() async {
if (!KeyboardVisibilityController().isVisible) {
return;
} else {
FocusScope.of(context).unfocus();
await Future.delayed(
const Duration(milliseconds: Constants.kKeyboardDelay), () {});
}
}
@override @override
void dispose() { Future<void> dispose() async {
_gameTitleTextController.dispose(); _gameTitleTextController.dispose();
for (var controller in _playerNameTextControllers) { for (var controller in _playerNameTextControllers) {
controller.dispose(); controller.dispose();