UI resposiveness fix on mobile

This commit is contained in:
2024-11-11 00:07:32 +01:00
parent c7233daec7
commit a857648c48

View File

@@ -44,7 +44,6 @@ class ExpectationInputPageState extends State<ExpectationInputPage> {
final FocusNode _frequencyFocusNode = FocusNode();
final FocusNode _squawkFocusNode = FocusNode();
// Neue Variablen
bool _saveSimbriefId = false;
static const String _simbriefIdKey = 'simbrief_id';
@@ -54,7 +53,6 @@ class ExpectationInputPageState extends State<ExpectationInputPage> {
_loadSavedSimbriefId();
}
// Methode zum Laden der gespeicherten ID
Future<void> _loadSavedSimbriefId() async {
final prefs = await SharedPreferences.getInstance();
final savedId = prefs.getString(_simbriefIdKey);
@@ -66,7 +64,6 @@ class ExpectationInputPageState extends State<ExpectationInputPage> {
}
}
// Methode zum Speichern der ID
Future<void> _saveSimbriefIdToPrefs() async {
final prefs = await SharedPreferences.getInstance();
if (_saveSimbriefId) {
@@ -100,7 +97,6 @@ class ExpectationInputPageState extends State<ExpectationInputPage> {
Uri.parse('https://www.simbrief.com/api/xml.fetcher.php?userid=${_simbriefIdController.text}&json=1'),
);
// Prüfe ob Widget noch mounted ist
if (!mounted) return;
if (response.statusCode == 200) {
@@ -116,15 +112,15 @@ class ExpectationInputPageState extends State<ExpectationInputPage> {
_expectedFrequencyController.text = '';
});
if (!mounted) return; // Zweiter Check vor ScaffoldMessenger
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('SimBrief Daten erfolgreich geladen')),
const SnackBar(content: Text('SimBrief data successfully loaded')),
);
}
} catch (e) {
if (!mounted) return; // Check vor Error-SnackBar
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Fehler beim Laden der SimBrief Daten: $e')),
SnackBar(content: Text('Error loading SimBrief data: $e')),
);
}
}
@@ -250,217 +246,246 @@ class ExpectationInputPageState extends State<ExpectationInputPage> {
),
],
),
body: GestureDetector(
// Dismiss the keyboard when tapping outside
onTap: () => FocusScope.of(context).unfocus(),
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// IntrinsicHeight Widget hinzufügen
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch, // Stretch hinzufügen
children: [
// Welcome Card - nimmt 60% der Breite
Expanded(
flex: 3,
child: Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
'Welcome to IFR Buddy!',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
Text(
'Just an easy tool for writing down IFR clearances without a pen.',
style: TextStyle(fontSize: 16),
),
],
),
),
),
),
const SizedBox(width: 16), // Abstand zwischen den Cards
// SimBrief Card - nimmt 40% der Breite
Expanded(
flex: 2,
child: Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'SimBrief Import',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
TextFormField(
controller: _simbriefIdController,
decoration: const InputDecoration(
labelText: 'SimBrief Pilot ID',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
Row(
children: [
Checkbox(
value: _saveSimbriefId,
onChanged: (bool? value) {
setState(() {
_saveSimbriefId = value ?? false;
});
_saveSimbriefIdToPrefs();
},
),
const Text('Save SimBrief ID'),
],
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _fetchSimbriefData,
child: const Text('Load SimBrief Data'),
),
),
],
),
),
),
),
],
body: LayoutBuilder(
builder: (context, constraints) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
// ConstrainedBox hinzufügen
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight - 100, // AppBar-Höhe abziehen
),
),
const SizedBox(height: 16),
Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Expected Clearance',
style: TextStyle(
fontSize: 22, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
const Text(
'Enter your expected clearance information below (Or use the SimBrief import). '
'Use the listening page or skip to the readback page.',
style: TextStyle(fontSize: 16),
textAlign: TextAlign.left,
),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.all(8.0),
),
Form(
key: _formKey,
child: Column(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (constraints.maxWidth > 600)
// Desktop Layout
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
buildTextField(
label: 'Clearance Limit',
controller: _expectedClearanceLimitController,
currentFocus: _clearanceLimitFocusNode,
nextFocus: _routeFocusNode,
keyboardType: TextInputType.text, // Standard keyboard
inputFormatters: [
// Allow letters, numbers, spaces, and hyphens
FilteringTextInputFormatter.allow(
RegExp(r'[A-Za-z0-9\s\-]')),
],
enableAutocorrect: false, // Disable autocorrect
enableSuggestions: false, // Disable suggestions
enableIMEPersonalizedLearning:
false, // iOS-specific
Expanded(
flex: 3,
child: _buildWelcomeCard(),
),
buildTextField(
label: 'Route/Sid',
controller: _expectedRouteController,
currentFocus: _routeFocusNode,
nextFocus: _altitudeFocusNode,
keyboardType: TextInputType.text, // Standard keyboard
inputFormatters: [
// Allow letters, numbers, spaces, and hyphens
FilteringTextInputFormatter.allow(
RegExp(r'[A-Za-z0-9\s\-]')),
],
enableAutocorrect: false, // Disable autocorrect
enableSuggestions: false, // Disable suggestions
enableIMEPersonalizedLearning:
false, // iOS-specific
),
buildTextField(
label: 'Altitude',
controller: _expectedAltitudeController,
currentFocus: _altitudeFocusNode,
nextFocus: _frequencyFocusNode, // Updated next focus
keyboardType: TextInputType.text, // Standard keyboard
inputFormatters: null, // No restrictions
enableAutocorrect: false, // Disable autocorrect
enableSuggestions: false, // Disable suggestions
enableIMEPersonalizedLearning:
false, // iOS-specific
),
buildTextField(
label: 'Departure Frequency', // Changed label
controller: _expectedFrequencyController,
currentFocus: _frequencyFocusNode,
nextFocus: _squawkFocusNode, // Next focus to Squawk
keyboardType: TextInputType.text, // Standard keyboard
inputFormatters: [
FrequencyInputFormatter(), // Handles decimal inputs
],
enableAutocorrect: false, // Disable autocorrect
enableSuggestions: false, // Disable suggestions
enableIMEPersonalizedLearning:
false, // iOS-specific
),
// buildTextField(
// label: 'Transponder (Squawk)', // Now last field
// controller: _expectedSquawkController,
// currentFocus: _squawkFocusNode,
// isLastField: true, // Mark as last field
// keyboardType: TextInputType.text, // Standard keyboard
// inputFormatters: [
// // Allow only digits 0-7 and limit to 4 characters
// FilteringTextInputFormatter.allow(
// RegExp(r'[0-7]')),
// LengthLimitingTextInputFormatter(4),
// ],
// enableAutocorrect: false, // Disable autocorrect
// enableSuggestions: false, // Disable suggestions
// enableIMEPersonalizedLearning:
// false, // iOS-specific
// ),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _navigateToComparisonPage,
child: const Text('Next'),
),
const SizedBox(height: 10),
TextButton(
onPressed: _skipReadback,
child: const Text('Skip to end'),
const SizedBox(width: 16),
Expanded(
flex: 2,
child: _buildSimbriefCard(),
),
],
),
)
else
// Mobile Layout
Column(
children: [
_buildWelcomeCard(),
const SizedBox(height: 16),
_buildSimbriefCard(),
],
),
],
),
_buildMainContent(),
],
),
),
],
),
),
);
},
),
);
}
// Hilfsmethoden zum Erstellen der Cards
Widget _buildWelcomeCard() {
return Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
'Welcome to IFR Buddy!',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
Text(
'Just an easy tool for writing down IFR clearances without a pen.',
style: TextStyle(fontSize: 16),
),
],
),
),
);
}
Widget _buildSimbriefCard() {
return Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'SimBrief Import',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
TextFormField(
controller: _simbriefIdController,
decoration: const InputDecoration(
labelText: 'SimBrief Pilot ID',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
Row(
children: [
Checkbox(
value: _saveSimbriefId,
onChanged: (bool? value) {
setState(() {
_saveSimbriefId = value ?? false;
});
_saveSimbriefIdToPrefs();
},
),
const Text('Save SimBrief ID'),
],
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _fetchSimbriefData,
child: const Text('Load SimBrief Data'),
),
),
],
),
),
);
}
Widget _buildMainContent() {
return Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Expected Clearance',
style: TextStyle(
fontSize: 22, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
const Text(
'Enter your expected clearance information below (Or use the SimBrief import). '
'Use the listening page or skip to the readback page.',
style: TextStyle(fontSize: 16),
textAlign: TextAlign.left,
),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.all(8.0),
),
Form(
key: _formKey,
child: Column(
children: [
buildTextField(
label: 'Clearance Limit',
controller: _expectedClearanceLimitController,
currentFocus: _clearanceLimitFocusNode,
nextFocus: _routeFocusNode,
keyboardType: TextInputType.text, // Standard keyboard
inputFormatters: [
// Allow letters, numbers, spaces, and hyphens
FilteringTextInputFormatter.allow(
RegExp(r'[A-Za-z0-9\s\-]')),
],
enableAutocorrect: false, // Disable autocorrect
enableSuggestions: false, // Disable suggestions
enableIMEPersonalizedLearning:
false, // iOS-specific
),
buildTextField(
label: 'Route/Sid',
controller: _expectedRouteController,
currentFocus: _routeFocusNode,
nextFocus: _altitudeFocusNode,
keyboardType: TextInputType.text, // Standard keyboard
inputFormatters: [
// Allow letters, numbers, spaces, and hyphens
FilteringTextInputFormatter.allow(
RegExp(r'[A-Za-z0-9\s\-]')),
],
enableAutocorrect: false, // Disable autocorrect
enableSuggestions: false, // Disable suggestions
enableIMEPersonalizedLearning:
false, // iOS-specific
),
buildTextField(
label: 'Altitude',
controller: _expectedAltitudeController,
currentFocus: _altitudeFocusNode,
nextFocus: _frequencyFocusNode, // Updated next focus
keyboardType: TextInputType.text, // Standard keyboard
inputFormatters: null, // No restrictions
enableAutocorrect: false, // Disable autocorrect
enableSuggestions: false, // Disable suggestions
enableIMEPersonalizedLearning:
false, // iOS-specific
),
buildTextField(
label: 'Departure Frequency', // Changed label
controller: _expectedFrequencyController,
currentFocus: _frequencyFocusNode,
nextFocus: _squawkFocusNode, // Next focus to Squawk
keyboardType: TextInputType.text, // Standard keyboard
inputFormatters: [
FrequencyInputFormatter(), // Handles decimal inputs
],
enableAutocorrect: false, // Disable autocorrect
enableSuggestions: false, // Disable suggestions
enableIMEPersonalizedLearning:
false, // iOS-specific
),
// buildTextField(
// label: 'Transponder (Squawk)', // Now last field
// controller: _expectedSquawkController,
// currentFocus: _squawkFocusNode,
// isLastField: true, // Mark as last field
// keyboardType: TextInputType.text, // Standard keyboard
// inputFormatters: [
// // Allow only digits 0-7 and limit to 4 characters
// FilteringTextInputFormatter.allow(
// RegExp(r'[0-7]')),
// LengthLimitingTextInputFormatter(4),
// ],
// enableAutocorrect: false, // Disable autocorrect
// enableSuggestions: false, // Disable suggestions
// enableIMEPersonalizedLearning:
// false, // iOS-specific
// ),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _navigateToComparisonPage,
child: const Text('Next'),
),
const SizedBox(height: 10),
TextButton(
onPressed: _skipReadback,
child: const Text('Skip to end'),
),
],
),
),
],
),
),
);