flutter fixes and pipeline speedup
This commit is contained in:
@@ -52,6 +52,14 @@ jobs:
|
||||
distribution: temurin
|
||||
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
|
||||
run: |
|
||||
mkdir -p "$ANDROID_SDK_ROOT"/cmdline-tools
|
||||
@@ -74,10 +82,29 @@ jobs:
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: ${{ env.FLUTTER_CHANNEL }}
|
||||
cache: true
|
||||
|
||||
- name: Allow all git directories (CI)
|
||||
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
|
||||
run: flutter pub get
|
||||
|
||||
@@ -160,10 +187,19 @@ jobs:
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: ${{ env.FLUTTER_CHANNEL }}
|
||||
cache: true
|
||||
|
||||
- name: Allow all git directories (CI)
|
||||
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
|
||||
run: flutter pub get
|
||||
|
||||
|
||||
@@ -76,8 +76,9 @@ class _DashboardState extends State<Dashboard> {
|
||||
if (isInitialLoading)
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
color:
|
||||
Theme.of(context).colorScheme.surface.withOpacity(0.7),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.surface.withOpacity(0.7),
|
||||
child: const Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -183,7 +184,8 @@ class _DashboardState extends State<Dashboard> {
|
||||
_buildCard(
|
||||
context,
|
||||
title: 'On this day',
|
||||
action: data.onThisDay
|
||||
action:
|
||||
data.onThisDay
|
||||
.where((leg) => leg.beginTime.year != DateTime.now().year)
|
||||
.length >
|
||||
5
|
||||
@@ -328,10 +330,10 @@ class _DashboardState extends State<Dashboard> {
|
||||
}
|
||||
|
||||
Widget _buildTripsCard(BuildContext context, DataService data) {
|
||||
final trips_unsorted = data.trips;
|
||||
final tripsUnsorted = data.trips;
|
||||
List trips = [];
|
||||
if (trips_unsorted.isNotEmpty) {
|
||||
trips = [...trips_unsorted]..sort((a, b) => b.tripId.compareTo(a.tripId));
|
||||
if (tripsUnsorted.isNotEmpty) {
|
||||
trips = [...tripsUnsorted]..sort((a, b) => b.tripId.compareTo(a.tripId));
|
||||
}
|
||||
return _buildCard(
|
||||
context,
|
||||
|
||||
@@ -100,8 +100,10 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
items: [
|
||||
const DropdownMenuItem(value: null, child: Text('No trip')),
|
||||
...sorted.map(
|
||||
(t) =>
|
||||
DropdownMenuItem<int?>(value: t.tripId, child: Text(t.tripName)),
|
||||
(t) => DropdownMenuItem<int?>(
|
||||
value: t.tripId,
|
||||
child: Text(t.tripName),
|
||||
),
|
||||
),
|
||||
],
|
||||
onChanged: (val) {
|
||||
@@ -304,7 +306,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
|
||||
if (_useManualMileage) {
|
||||
final body = {
|
||||
"leg_trip": _selectedTripId ?? null,
|
||||
"leg_trip": _selectedTripId,
|
||||
"leg_start": startVal,
|
||||
"leg_end": endVal,
|
||||
"leg_begin_time": _legDateTime.toIso8601String(),
|
||||
@@ -318,7 +320,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
await api.post('/add/manual', body);
|
||||
} else {
|
||||
final body = {
|
||||
"leg_trip": _selectedTripId ?? null,
|
||||
"leg_trip": _selectedTripId,
|
||||
"leg_begin_time": _legDateTime.toIso8601String(),
|
||||
"leg_route": routeStations,
|
||||
"leg_notes": _notesController.text.trim(),
|
||||
@@ -429,14 +431,15 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
_useManualMileage = data['useManualMileage'] ?? _useManualMileage;
|
||||
_selectedTripId = data['selectedTripId'];
|
||||
if (data['routeResult'] is Map<String, dynamic>) {
|
||||
_routeResult =
|
||||
RouteResult.fromJson(Map<String, dynamic>.from(data['routeResult']));
|
||||
_routeResult = RouteResult.fromJson(
|
||||
Map<String, dynamic>.from(data['routeResult']),
|
||||
);
|
||||
_mileageController.text = _routeResult!.distance.toStringAsFixed(2);
|
||||
}
|
||||
if (data['tractionItems'] is List) {
|
||||
_restoreTractionItems(List<Map<String, dynamic>>.from(
|
||||
data['tractionItems'].cast<Map>(),
|
||||
));
|
||||
_restoreTractionItems(
|
||||
List<Map<String, dynamic>>.from(data['tractionItems'].cast<Map>()),
|
||||
);
|
||||
}
|
||||
});
|
||||
_startController.text = data['start'] ?? '';
|
||||
@@ -793,9 +796,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
if (trailing != null) trailing,
|
||||
],
|
||||
|
||||
@@ -68,10 +68,13 @@ class _TractionPageState extends State<TractionPage> {
|
||||
}
|
||||
|
||||
bool get _hasFilters {
|
||||
final dynamicFieldsUsed = _dynamicControllers.values
|
||||
.any((controller) => controller.text.trim().isNotEmpty) ||
|
||||
_enumSelections.values
|
||||
.any((value) => (value ?? '').toString().trim().isNotEmpty);
|
||||
final dynamicFieldsUsed =
|
||||
_dynamicControllers.values.any(
|
||||
(controller) => controller.text.trim().isNotEmpty,
|
||||
) ||
|
||||
_enumSelections.values.any(
|
||||
(value) => (value ?? '').toString().trim().isNotEmpty,
|
||||
);
|
||||
|
||||
return [
|
||||
_selectedClass,
|
||||
@@ -109,7 +112,11 @@ class _TractionPageState extends State<TractionPage> {
|
||||
}
|
||||
|
||||
void _clearFilters() {
|
||||
for (final controller in [_classController, _numberController, _nameController]) {
|
||||
for (final controller in [
|
||||
_classController,
|
||||
_numberController,
|
||||
_nameController,
|
||||
]) {
|
||||
controller.clear();
|
||||
}
|
||||
for (final controller in _dynamicControllers.values) {
|
||||
@@ -135,9 +142,13 @@ class _TractionPageState extends State<TractionPage> {
|
||||
List<EventField> _activeEventFields(List<EventField> fields) {
|
||||
return fields
|
||||
.where(
|
||||
(field) =>
|
||||
!['class', 'number', 'name', 'build date', 'build_date']
|
||||
.contains(field.name.toLowerCase()),
|
||||
(field) => ![
|
||||
'class',
|
||||
'number',
|
||||
'name',
|
||||
'build date',
|
||||
'build_date',
|
||||
].contains(field.name.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
@@ -147,7 +158,10 @@ class _TractionPageState extends State<TractionPage> {
|
||||
if (field.enumValues != null) {
|
||||
_enumSelections.putIfAbsent(field.name, () => null);
|
||||
} else {
|
||||
_dynamicControllers.putIfAbsent(field.name, () => TextEditingController());
|
||||
_dynamicControllers.putIfAbsent(
|
||||
field.name,
|
||||
() => TextEditingController(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,7 +242,12 @@ class _TractionPageState extends State<TractionPage> {
|
||||
);
|
||||
},
|
||||
fieldViewBuilder:
|
||||
(context, controller, focusNode, onFieldSubmitted) {
|
||||
(
|
||||
context,
|
||||
controller,
|
||||
focusNode,
|
||||
onFieldSubmitted,
|
||||
) {
|
||||
return TextField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
@@ -323,7 +342,9 @@ class _TractionPageState extends State<TractionPage> {
|
||||
: Icons.expand_more,
|
||||
),
|
||||
label: Text(
|
||||
_showAdvancedFilters ? 'Hide filters' : 'More filters',
|
||||
_showAdvancedFilters
|
||||
? 'Hide filters'
|
||||
: 'More filters',
|
||||
),
|
||||
),
|
||||
ElevatedButton.icon(
|
||||
@@ -344,7 +365,9 @@ class _TractionPageState extends State<TractionPage> {
|
||||
? const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
),
|
||||
)
|
||||
: extraFields.isEmpty
|
||||
@@ -404,8 +427,9 @@ class _TractionPageState extends State<TractionPage> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: OutlinedButton.icon(
|
||||
onPressed:
|
||||
data.isTractionLoading ? null : () => _refreshTraction(append: true),
|
||||
onPressed: data.isTractionLoading
|
||||
? null
|
||||
: () => _refreshTraction(append: true),
|
||||
icon: data.isTractionLoading
|
||||
? const SizedBox(
|
||||
height: 14,
|
||||
@@ -580,7 +604,11 @@ class _TractionPageState extends State<TractionPage> {
|
||||
(Color, Color) _statusChipColors(BuildContext context, String status) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
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(
|
||||
base.withOpacity(isDark ? bgOpacity + 0.07 : bgOpacity),
|
||||
scheme.surface,
|
||||
@@ -719,7 +747,10 @@ class _TractionPageState extends State<TractionPage> {
|
||||
) {
|
||||
final width = isMobile ? double.infinity : 220.0;
|
||||
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 safeValue = options.contains(currentValue) ? currentValue : null;
|
||||
return SizedBox(
|
||||
@@ -732,14 +763,9 @@ class _TractionPageState extends State<TractionPage> {
|
||||
),
|
||||
items: [
|
||||
const DropdownMenuItem(value: null, child: Text('Any')),
|
||||
...options
|
||||
.map(
|
||||
(value) => DropdownMenuItem(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
...options.map(
|
||||
(value) => DropdownMenuItem(value: value, child: Text(value)),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
],
|
||||
onChanged: (val) {
|
||||
setState(() {
|
||||
@@ -757,7 +783,9 @@ class _TractionPageState extends State<TractionPage> {
|
||||
TextInputType? inputType;
|
||||
if (field.type != null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,8 +261,8 @@ class DataService extends ChangeNotifier {
|
||||
try {
|
||||
final json = await api.get('/trips/legs-and-stats');
|
||||
if (json is List) {
|
||||
final trip_map = json.map((e) => TripDetail.fromJson(e)).toList();
|
||||
_tripDetails = [...trip_map]..sort((a, b) => b.id.compareTo(a.id));
|
||||
final tripMap = json.map((e) => TripDetail.fromJson(e)).toList();
|
||||
_tripDetails = [...tripMap]..sort((a, b) => b.id.compareTo(a.id));
|
||||
} else {
|
||||
_tripDetails = [];
|
||||
}
|
||||
@@ -360,12 +360,12 @@ class DataService extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
if (raw != null) {
|
||||
final trip_map = raw
|
||||
final tripMap = raw
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map((e) => TripSummary.fromJson(e))
|
||||
.toList();
|
||||
|
||||
_tripList = [...trip_map]..sort((a, b) => b.tripId.compareTo(a.tripId));
|
||||
_tripList = [...tripMap]..sort((a, b) => b.tripId.compareTo(a.tripId));
|
||||
} else {
|
||||
debugPrint('Unexpected trip list response: $json');
|
||||
_tripList = [];
|
||||
|
||||
Reference in New Issue
Block a user