// lib/widgets/activity/dialogs/activity_db_fields_dialog.dart import 'package:aves/model/activity/activity_entry.dart'; import 'package:aves/widgets/activity/utils/activity_formatters.dart'; import 'package:flutter/material.dart'; Future showActivityDbFieldsDialog({ required BuildContext context, required ActivityEntry entry, }) async { final rows = _activityEntryDbRows(entry); await showDialog( context: context, builder: (context) { return AlertDialog( title: const Text('Dettagli DB attività'), content: SizedBox( width: double.maxFinite, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: rows .map( (row) => _DbFieldLine( label: row.$1, value: row.$2, ), ) .toList(), ), ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Chiudi'), ), ], ); }, ); } List<(String, String)> _activityEntryDbRows(ActivityEntry e) { String v(Object? value) { if (value == null) return '-'; if (value is String && value.isEmpty) return '-'; return '$value'; } String millisDate(int? millis) { if (millis == null) return '-'; final date = DateTime.fromMillisecondsSinceEpoch(millis).toLocal(); final day = date.day.toString().padLeft(2, '0'); final month = date.month.toString().padLeft(2, '0'); final year = date.year.toString().padLeft(4, '0'); final hour = date.hour.toString().padLeft(2, '0'); final minute = date.minute.toString().padLeft(2, '0'); final second = date.second.toString().padLeft(2, '0'); return '$day/$month/$year $hour:$minute:$second'; } String millisValue(int? millis) { if (millis == null) return '-'; return '$millis (${millisDate(millis)})'; } String bytes(int? value) { if (value == null) return '-'; if (value >= 1024 * 1024) { return '${(value / (1024 * 1024)).toStringAsFixed(2)} MB ($value bytes)'; } if (value >= 1024) { return '${(value / 1024).toStringAsFixed(2)} KB ($value bytes)'; } return '$value bytes'; } String distance(double? meters) { if (meters == null) return '-'; return '${(meters / 1000).toStringAsFixed(3)} km (${meters.toStringAsFixed(2)} m)'; } String elevation(double? meters) { if (meters == null) return '-'; return '${meters.toStringAsFixed(2)} m'; } String speed(double? mps) { if (mps == null) return '-'; final kmh = mps * 3.6; return '${mps.toStringAsFixed(3)} m/s (${kmh.toStringAsFixed(2)} km/h)'; } String pace(double? secPerKm) { if (secPerKm == null) return '-'; final totalSeconds = secPerKm.round(); final minutes = totalSeconds ~/ 60; final seconds = totalSeconds % 60; return '${minutes}m ${seconds.toString().padLeft(2, '0')}s / km (${secPerKm.toStringAsFixed(2)} s/km)'; } String coordinate(double? value) { if (value == null) return '-'; return value.toStringAsFixed(7); } return [ ('id', v(e.id)), ('origin', v(e.origin)), ('uri', v(e.uri)), ('relativePath', v(e.relativePath)), ('directoryName', v(e.directoryName)), ('fileName', v(e.fileName)), ('fileExtension', v(e.fileExtension)), ('format', v(e.format)), ('bestName', v(e.bestName)), ('displayName', v(e.displayName)), ('routeName', v(e.routeName)), ('title', v(e.title)), ('description', v(e.description)), ('notes', v(e.notes)), ('sport', v(e.sport)), ('activityType', v(e.activityType)), ('deviceManufacturer', v(e.deviceManufacturer)), ('deviceModel', v(e.deviceModel)), ('sourceApp', v(e.sourceApp)), ('startTimeMillis', millisValue(e.startTimeMillis)), ('endTimeMillis', millisValue(e.endTimeMillis)), ('durationMillis', v(e.durationMillis)), ('durationFormatted', ActivityFormatters.entryDuration(e.durationMillis)), ('distanceMeters', distance(e.distanceMeters)), ('elevationGainMeters', elevation(e.elevationGainMeters)), ('elevationLossMeters', elevation(e.elevationLossMeters)), ('minElevationMeters', elevation(e.minElevationMeters)), ('maxElevationMeters', elevation(e.maxElevationMeters)), ('fileDistanceMeters', distance(e.fileDistanceMeters)), ('fileElevationGainMeters', elevation(e.fileElevationGainMeters)), ('computedDistanceMeters', distance(e.computedDistanceMeters)), ('computedElevationGainMeters', elevation(e.computedElevationGainMeters)), ('averageSpeedMps', speed(e.averageSpeedMps)), ('maxSpeedMps', speed(e.maxSpeedMps)), ('averagePaceSecPerKm', pace(e.averagePaceSecPerKm)), ('averageHeartRate', v(e.averageHeartRate)), ('maxHeartRate', v(e.maxHeartRate)), ('averageCadence', v(e.averageCadence)), ('maxCadence', v(e.maxCadence)), ('calories', v(e.calories)), ('powerAvg', v(e.powerAvg)), ('powerMax', v(e.powerMax)), ('pointCount', v(e.pointCount)), ('segmentCount', v(e.segmentCount)), ('lapCount', v(e.lapCount)), ('minLatitude', coordinate(e.minLatitude)), ('maxLatitude', coordinate(e.maxLatitude)), ('minLongitude', coordinate(e.minLongitude)), ('maxLongitude', coordinate(e.maxLongitude)), ('centerLatitude', coordinate(e.centerLatitude)), ('centerLongitude', coordinate(e.centerLongitude)), ('sizeBytes', bytes(e.sizeBytes)), ('lastModifiedMillis', millisValue(e.lastModifiedMillis)), ('dateAddedMillis', millisValue(e.dateAddedMillis)), ('dateModifiedMillis', millisValue(e.dateModifiedMillis)), ('lastScanMillis', millisValue(e.lastScanMillis)), ('isFavorite', v(e.isFavorite)), ('isHidden', v(e.isHidden)), ('rating', v(e.rating)), ('tags', v(e.tags)), ('scanStatus', v(e.scanStatus)), ('scanError', v(e.scanError)), ('diagnostics', v(e.diagnostics)), ]; } class _DbFieldLine extends StatelessWidget { final String label; final String value; const _DbFieldLine({ required this.label, required this.value, }); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: theme.textTheme.labelMedium?.copyWith( fontWeight: FontWeight.w700, ), ), const SizedBox(height: 2), SelectableText( value, style: theme.textTheme.bodySmall, ), const Divider(height: 12), ], ), ); } }