flutter fixes and pipeline speedup
Some checks failed
Release / meta (push) Successful in 20s
Release / linux-build (push) Successful in 36m32s
Release / release-dev (push) Has been cancelled
Release / release-master (push) Has been cancelled
Release / android-build (push) Has been cancelled

This commit is contained in:
2025-12-14 11:20:39 +00:00
parent eb01cf0e8e
commit a2b38a7aec
5 changed files with 173 additions and 104 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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,
],

View File

@@ -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);
}
}

View File

@@ -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 = [];