flutter fixes and pipeline speedup
This commit is contained in:
@@ -52,6 +52,14 @@ jobs:
|
|||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
|
|
||||||
|
- name: Cache Android SDK
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.ANDROID_SDK_ROOT }}
|
||||||
|
key: android-sdk-${{ runner.os }}-java${{ env.JAVA_VERSION }}-platform33-buildtools33.0.2
|
||||||
|
restore-keys: |
|
||||||
|
android-sdk-${{ runner.os }}-java${{ env.JAVA_VERSION }}-
|
||||||
|
|
||||||
- name: Install Android SDK
|
- name: Install Android SDK
|
||||||
run: |
|
run: |
|
||||||
mkdir -p "$ANDROID_SDK_ROOT"/cmdline-tools
|
mkdir -p "$ANDROID_SDK_ROOT"/cmdline-tools
|
||||||
@@ -74,10 +82,29 @@ jobs:
|
|||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: ${{ env.FLUTTER_CHANNEL }}
|
channel: ${{ env.FLUTTER_CHANNEL }}
|
||||||
|
cache: true
|
||||||
|
|
||||||
- name: Allow all git directories (CI)
|
- name: Allow all git directories (CI)
|
||||||
run: git config --global --add safe.directory '*'
|
run: git config --global --add safe.directory '*'
|
||||||
|
|
||||||
|
- name: Cache pub packages
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.pub-cache
|
||||||
|
key: flutter-pub-${{ runner.os }}-${{ hashFiles('pubspec.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
flutter-pub-${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: Cache Gradle
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('android/**/*.gradle*', 'android/**/*.properties') }}
|
||||||
|
restore-keys: |
|
||||||
|
gradle-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Flutter dependencies
|
- name: Flutter dependencies
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
|
|
||||||
@@ -160,10 +187,19 @@ jobs:
|
|||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: ${{ env.FLUTTER_CHANNEL }}
|
channel: ${{ env.FLUTTER_CHANNEL }}
|
||||||
|
cache: true
|
||||||
|
|
||||||
- name: Allow all git directories (CI)
|
- name: Allow all git directories (CI)
|
||||||
run: git config --global --add safe.directory '*'
|
run: git config --global --add safe.directory '*'
|
||||||
|
|
||||||
|
- name: Cache pub packages
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.pub-cache
|
||||||
|
key: flutter-pub-${{ runner.os }}-${{ hashFiles('pubspec.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
flutter-pub-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Flutter dependencies
|
- name: Flutter dependencies
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
|
|
||||||
|
|||||||
@@ -76,8 +76,9 @@ class _DashboardState extends State<Dashboard> {
|
|||||||
if (isInitialLoading)
|
if (isInitialLoading)
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Container(
|
child: Container(
|
||||||
color:
|
color: Theme.of(
|
||||||
Theme.of(context).colorScheme.surface.withOpacity(0.7),
|
context,
|
||||||
|
).colorScheme.surface.withOpacity(0.7),
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@@ -183,7 +184,8 @@ class _DashboardState extends State<Dashboard> {
|
|||||||
_buildCard(
|
_buildCard(
|
||||||
context,
|
context,
|
||||||
title: 'On this day',
|
title: 'On this day',
|
||||||
action: data.onThisDay
|
action:
|
||||||
|
data.onThisDay
|
||||||
.where((leg) => leg.beginTime.year != DateTime.now().year)
|
.where((leg) => leg.beginTime.year != DateTime.now().year)
|
||||||
.length >
|
.length >
|
||||||
5
|
5
|
||||||
@@ -328,10 +330,10 @@ class _DashboardState extends State<Dashboard> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTripsCard(BuildContext context, DataService data) {
|
Widget _buildTripsCard(BuildContext context, DataService data) {
|
||||||
final trips_unsorted = data.trips;
|
final tripsUnsorted = data.trips;
|
||||||
List trips = [];
|
List trips = [];
|
||||||
if (trips_unsorted.isNotEmpty) {
|
if (tripsUnsorted.isNotEmpty) {
|
||||||
trips = [...trips_unsorted]..sort((a, b) => b.tripId.compareTo(a.tripId));
|
trips = [...tripsUnsorted]..sort((a, b) => b.tripId.compareTo(a.tripId));
|
||||||
}
|
}
|
||||||
return _buildCard(
|
return _buildCard(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
|||||||
final tripIds = sorted.map((t) => t.tripId).toSet();
|
final tripIds = sorted.map((t) => t.tripId).toSet();
|
||||||
final selectedValue =
|
final selectedValue =
|
||||||
(_selectedTripId != null && tripIds.contains(_selectedTripId))
|
(_selectedTripId != null && tripIds.contains(_selectedTripId))
|
||||||
? _selectedTripId
|
? _selectedTripId
|
||||||
: null;
|
: null;
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -100,8 +100,10 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
|||||||
items: [
|
items: [
|
||||||
const DropdownMenuItem(value: null, child: Text('No trip')),
|
const DropdownMenuItem(value: null, child: Text('No trip')),
|
||||||
...sorted.map(
|
...sorted.map(
|
||||||
(t) =>
|
(t) => DropdownMenuItem<int?>(
|
||||||
DropdownMenuItem<int?>(value: t.tripId, child: Text(t.tripName)),
|
value: t.tripId,
|
||||||
|
child: Text(t.tripName),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
@@ -304,7 +306,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
|||||||
|
|
||||||
if (_useManualMileage) {
|
if (_useManualMileage) {
|
||||||
final body = {
|
final body = {
|
||||||
"leg_trip": _selectedTripId ?? null,
|
"leg_trip": _selectedTripId,
|
||||||
"leg_start": startVal,
|
"leg_start": startVal,
|
||||||
"leg_end": endVal,
|
"leg_end": endVal,
|
||||||
"leg_begin_time": _legDateTime.toIso8601String(),
|
"leg_begin_time": _legDateTime.toIso8601String(),
|
||||||
@@ -318,7 +320,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
|||||||
await api.post('/add/manual', body);
|
await api.post('/add/manual', body);
|
||||||
} else {
|
} else {
|
||||||
final body = {
|
final body = {
|
||||||
"leg_trip": _selectedTripId ?? null,
|
"leg_trip": _selectedTripId,
|
||||||
"leg_begin_time": _legDateTime.toIso8601String(),
|
"leg_begin_time": _legDateTime.toIso8601String(),
|
||||||
"leg_route": routeStations,
|
"leg_route": routeStations,
|
||||||
"leg_notes": _notesController.text.trim(),
|
"leg_notes": _notesController.text.trim(),
|
||||||
@@ -429,14 +431,15 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
|||||||
_useManualMileage = data['useManualMileage'] ?? _useManualMileage;
|
_useManualMileage = data['useManualMileage'] ?? _useManualMileage;
|
||||||
_selectedTripId = data['selectedTripId'];
|
_selectedTripId = data['selectedTripId'];
|
||||||
if (data['routeResult'] is Map<String, dynamic>) {
|
if (data['routeResult'] is Map<String, dynamic>) {
|
||||||
_routeResult =
|
_routeResult = RouteResult.fromJson(
|
||||||
RouteResult.fromJson(Map<String, dynamic>.from(data['routeResult']));
|
Map<String, dynamic>.from(data['routeResult']),
|
||||||
|
);
|
||||||
_mileageController.text = _routeResult!.distance.toStringAsFixed(2);
|
_mileageController.text = _routeResult!.distance.toStringAsFixed(2);
|
||||||
}
|
}
|
||||||
if (data['tractionItems'] is List) {
|
if (data['tractionItems'] is List) {
|
||||||
_restoreTractionItems(List<Map<String, dynamic>>.from(
|
_restoreTractionItems(
|
||||||
data['tractionItems'].cast<Map>(),
|
List<Map<String, dynamic>>.from(data['tractionItems'].cast<Map>()),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_startController.text = data['start'] ?? '';
|
_startController.text = data['start'] ?? '';
|
||||||
@@ -609,34 +612,34 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
|||||||
final mileagePanel = _section(
|
final mileagePanel = _section(
|
||||||
'Mileage',
|
'Mileage',
|
||||||
[
|
[
|
||||||
if (_useManualMileage)
|
if (_useManualMileage)
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _mileageController,
|
controller: _mileageController,
|
||||||
keyboardType: const TextInputType.numberWithOptions(
|
keyboardType: const TextInputType.numberWithOptions(
|
||||||
decimal: true,
|
decimal: true,
|
||||||
|
),
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Mileage (mi)',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (_routeResult != null)
|
||||||
|
ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
title: const Text('Calculated mileage'),
|
||||||
|
subtitle: Text(
|
||||||
|
'${_routeResult!.distance.toStringAsFixed(2)} mi',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
decoration: const InputDecoration(
|
if (!_useManualMileage)
|
||||||
labelText: 'Mileage (mi)',
|
Align(
|
||||||
border: OutlineInputBorder(),
|
alignment: Alignment.centerLeft,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: _openCalculator,
|
||||||
|
icon: const Icon(Icons.calculate),
|
||||||
|
label: const Text('Open mileage calculator'),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
else if (_routeResult != null)
|
|
||||||
ListTile(
|
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
title: const Text('Calculated mileage'),
|
|
||||||
subtitle: Text(
|
|
||||||
'${_routeResult!.distance.toStringAsFixed(2)} mi',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!_useManualMileage)
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
onPressed: _openCalculator,
|
|
||||||
icon: const Icon(Icons.calculate),
|
|
||||||
label: const Text('Open mileage calculator'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
trailing: FilterChip(
|
trailing: FilterChip(
|
||||||
label: Text(_useManualMileage ? 'Manual' : 'Automatic'),
|
label: Text(_useManualMileage ? 'Manual' : 'Automatic'),
|
||||||
@@ -793,9 +796,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
context,
|
fontWeight: FontWeight.bold,
|
||||||
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
),
|
||||||
),
|
),
|
||||||
if (trailing != null) trailing,
|
if (trailing != null) trailing,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -68,17 +68,20 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool get _hasFilters {
|
bool get _hasFilters {
|
||||||
final dynamicFieldsUsed = _dynamicControllers.values
|
final dynamicFieldsUsed =
|
||||||
.any((controller) => controller.text.trim().isNotEmpty) ||
|
_dynamicControllers.values.any(
|
||||||
_enumSelections.values
|
(controller) => controller.text.trim().isNotEmpty,
|
||||||
.any((value) => (value ?? '').toString().trim().isNotEmpty);
|
) ||
|
||||||
|
_enumSelections.values.any(
|
||||||
|
(value) => (value ?? '').toString().trim().isNotEmpty,
|
||||||
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
_selectedClass,
|
_selectedClass,
|
||||||
_classController.text,
|
_classController.text,
|
||||||
_numberController.text,
|
_numberController.text,
|
||||||
_nameController.text,
|
_nameController.text,
|
||||||
].any((value) => (value ?? '').toString().trim().isNotEmpty) ||
|
].any((value) => (value ?? '').toString().trim().isNotEmpty) ||
|
||||||
dynamicFieldsUsed;
|
dynamicFieldsUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +112,11 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _clearFilters() {
|
void _clearFilters() {
|
||||||
for (final controller in [_classController, _numberController, _nameController]) {
|
for (final controller in [
|
||||||
|
_classController,
|
||||||
|
_numberController,
|
||||||
|
_nameController,
|
||||||
|
]) {
|
||||||
controller.clear();
|
controller.clear();
|
||||||
}
|
}
|
||||||
for (final controller in _dynamicControllers.values) {
|
for (final controller in _dynamicControllers.values) {
|
||||||
@@ -135,9 +142,13 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
List<EventField> _activeEventFields(List<EventField> fields) {
|
List<EventField> _activeEventFields(List<EventField> fields) {
|
||||||
return fields
|
return fields
|
||||||
.where(
|
.where(
|
||||||
(field) =>
|
(field) => ![
|
||||||
!['class', 'number', 'name', 'build date', 'build_date']
|
'class',
|
||||||
.contains(field.name.toLowerCase()),
|
'number',
|
||||||
|
'name',
|
||||||
|
'build date',
|
||||||
|
'build_date',
|
||||||
|
].contains(field.name.toLowerCase()),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
@@ -147,7 +158,10 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
if (field.enumValues != null) {
|
if (field.enumValues != null) {
|
||||||
_enumSelections.putIfAbsent(field.name, () => null);
|
_enumSelections.putIfAbsent(field.name, () => null);
|
||||||
} else {
|
} else {
|
||||||
_dynamicControllers.putIfAbsent(field.name, () => TextEditingController());
|
_dynamicControllers.putIfAbsent(
|
||||||
|
field.name,
|
||||||
|
() => TextEditingController(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,17 +242,22 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
fieldViewBuilder:
|
fieldViewBuilder:
|
||||||
(context, controller, focusNode, onFieldSubmitted) {
|
(
|
||||||
return TextField(
|
context,
|
||||||
controller: controller,
|
controller,
|
||||||
focusNode: focusNode,
|
focusNode,
|
||||||
decoration: const InputDecoration(
|
onFieldSubmitted,
|
||||||
labelText: 'Class',
|
) {
|
||||||
border: OutlineInputBorder(),
|
return TextField(
|
||||||
),
|
controller: controller,
|
||||||
onSubmitted: (_) => _refreshTraction(),
|
focusNode: focusNode,
|
||||||
);
|
decoration: const InputDecoration(
|
||||||
},
|
labelText: 'Class',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
onSubmitted: (_) => _refreshTraction(),
|
||||||
|
);
|
||||||
|
},
|
||||||
optionsViewBuilder: (context, onSelected, options) {
|
optionsViewBuilder: (context, onSelected, options) {
|
||||||
final optionList = options.toList();
|
final optionList = options.toList();
|
||||||
if (optionList.isEmpty) {
|
if (optionList.isEmpty) {
|
||||||
@@ -323,7 +342,9 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
: Icons.expand_more,
|
: Icons.expand_more,
|
||||||
),
|
),
|
||||||
label: Text(
|
label: Text(
|
||||||
_showAdvancedFilters ? 'Hide filters' : 'More filters',
|
_showAdvancedFilters
|
||||||
|
? 'Hide filters'
|
||||||
|
: 'More filters',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
@@ -344,24 +365,26 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
? const Center(
|
? const Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: extraFields.isEmpty
|
: extraFields.isEmpty
|
||||||
? const Text('No extra filters available right now.')
|
? const Text('No extra filters available right now.')
|
||||||
: Wrap(
|
: Wrap(
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
runSpacing: 12,
|
runSpacing: 12,
|
||||||
children: extraFields
|
children: extraFields
|
||||||
.map(
|
.map(
|
||||||
(field) => _buildFilterInput(
|
(field) => _buildFilterInput(
|
||||||
context,
|
context,
|
||||||
field,
|
field,
|
||||||
isMobile,
|
isMobile,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
secondChild: const SizedBox.shrink(),
|
secondChild: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
@@ -404,8 +427,9 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
child: OutlinedButton.icon(
|
child: OutlinedButton.icon(
|
||||||
onPressed:
|
onPressed: data.isTractionLoading
|
||||||
data.isTractionLoading ? null : () => _refreshTraction(append: true),
|
? null
|
||||||
|
: () => _refreshTraction(append: true),
|
||||||
icon: data.isTractionLoading
|
icon: data.isTractionLoading
|
||||||
? const SizedBox(
|
? const SizedBox(
|
||||||
height: 14,
|
height: 14,
|
||||||
@@ -580,7 +604,11 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
(Color, Color) _statusChipColors(BuildContext context, String status) {
|
(Color, Color) _statusChipColors(BuildContext context, String status) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
final isDark = scheme.brightness == Brightness.dark;
|
final isDark = scheme.brightness == Brightness.dark;
|
||||||
Color blend(Color base, {double bgOpacity = 0.18, double fgOpacity = 0.82}) {
|
Color blend(
|
||||||
|
Color base, {
|
||||||
|
double bgOpacity = 0.18,
|
||||||
|
double fgOpacity = 0.82,
|
||||||
|
}) {
|
||||||
final bg = Color.alphaBlend(
|
final bg = Color.alphaBlend(
|
||||||
base.withOpacity(isDark ? bgOpacity + 0.07 : bgOpacity),
|
base.withOpacity(isDark ? bgOpacity + 0.07 : bgOpacity),
|
||||||
scheme.surface,
|
scheme.surface,
|
||||||
@@ -719,7 +747,10 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
) {
|
) {
|
||||||
final width = isMobile ? double.infinity : 220.0;
|
final width = isMobile ? double.infinity : 220.0;
|
||||||
if (field.enumValues != null && field.enumValues!.isNotEmpty) {
|
if (field.enumValues != null && field.enumValues!.isNotEmpty) {
|
||||||
final options = field.enumValues!.map((e) => e.toString()).toSet().toList();
|
final options = field.enumValues!
|
||||||
|
.map((e) => e.toString())
|
||||||
|
.toSet()
|
||||||
|
.toList();
|
||||||
final currentValue = _enumSelections[field.name];
|
final currentValue = _enumSelections[field.name];
|
||||||
final safeValue = options.contains(currentValue) ? currentValue : null;
|
final safeValue = options.contains(currentValue) ? currentValue : null;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
@@ -732,14 +763,9 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
),
|
),
|
||||||
items: [
|
items: [
|
||||||
const DropdownMenuItem(value: null, child: Text('Any')),
|
const DropdownMenuItem(value: null, child: Text('Any')),
|
||||||
...options
|
...options.map(
|
||||||
.map(
|
(value) => DropdownMenuItem(value: value, child: Text(value)),
|
||||||
(value) => DropdownMenuItem(
|
),
|
||||||
value: value,
|
|
||||||
child: Text(value),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
],
|
],
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -757,7 +783,9 @@ class _TractionPageState extends State<TractionPage> {
|
|||||||
TextInputType? inputType;
|
TextInputType? inputType;
|
||||||
if (field.type != null) {
|
if (field.type != null) {
|
||||||
final type = field.type!.toLowerCase();
|
final type = field.type!.toLowerCase();
|
||||||
if (type.contains('int') || type.contains('num') || type.contains('double')) {
|
if (type.contains('int') ||
|
||||||
|
type.contains('num') ||
|
||||||
|
type.contains('double')) {
|
||||||
inputType = const TextInputType.numberWithOptions(decimal: true);
|
inputType = const TextInputType.numberWithOptions(decimal: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,8 +261,8 @@ class DataService extends ChangeNotifier {
|
|||||||
try {
|
try {
|
||||||
final json = await api.get('/trips/legs-and-stats');
|
final json = await api.get('/trips/legs-and-stats');
|
||||||
if (json is List) {
|
if (json is List) {
|
||||||
final trip_map = json.map((e) => TripDetail.fromJson(e)).toList();
|
final tripMap = json.map((e) => TripDetail.fromJson(e)).toList();
|
||||||
_tripDetails = [...trip_map]..sort((a, b) => b.id.compareTo(a.id));
|
_tripDetails = [...tripMap]..sort((a, b) => b.id.compareTo(a.id));
|
||||||
} else {
|
} else {
|
||||||
_tripDetails = [];
|
_tripDetails = [];
|
||||||
}
|
}
|
||||||
@@ -360,12 +360,12 @@ class DataService extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (raw != null) {
|
if (raw != null) {
|
||||||
final trip_map = raw
|
final tripMap = raw
|
||||||
.whereType<Map<String, dynamic>>()
|
.whereType<Map<String, dynamic>>()
|
||||||
.map((e) => TripSummary.fromJson(e))
|
.map((e) => TripSummary.fromJson(e))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
_tripList = [...trip_map]..sort((a, b) => b.tripId.compareTo(a.tripId));
|
_tripList = [...tripMap]..sort((a, b) => b.tripId.compareTo(a.tripId));
|
||||||
} else {
|
} else {
|
||||||
debugPrint('Unexpected trip list response: $json');
|
debugPrint('Unexpected trip list response: $json');
|
||||||
_tripList = [];
|
_tripList = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user