screen-locker/stronglift_replacement/workout_app/lib/services/sync_service.dart
Krzysztof kuhy Rudnicki 7722260eeb Fix workout_app service tests on non-Android hosts
Pre-existing failures unrelated to the manual-workout feature, exposed once the
pre-push flutter gate started running the Dart suite:

- http_server_service / sync_service: getExternalStorageDirectory() throws
  UnsupportedError (an Error, not an Exception) on non-Android platforms, so the
  `on Exception` fallbacks didn't catch it and it escaped, failing start() and
  writeWorkoutResult(). External storage is Android-only, so guard the call with
  Platform.isAndroid instead of trying to catch a platform Error.
- sync_service_test: the "updates HttpServerService" assertion expected compact
  JSON ("workout_type":"A") but the payload is pretty-printed
  ("workout_type": "A"); fixed the expectation to match.

Full workout_app suite (191 tests) now passes on this host.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PM3auNTifaVgcXWDizZrjH
2026-07-13 12:47:55 +02:00

69 lines
2.3 KiB
Dart

/// Writes workout result JSON to external storage (ADB) and the HTTP server.
library;
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:workout_app/models/workout_session.dart';
import 'package:workout_app/services/http_server_service.dart';
/// Path on the phone's external storage where the PC reads workout data.
const String kSyncFilePath = '/sdcard/workout_result.json';
/// Handles writing completed workout sessions to disk and the HTTP server.
class SyncService {
/// Writes [session] as JSON to external storage and updates the HTTP server.
///
/// Falls back to app-external directory if /sdcard/ is not writable.
Future<SyncResult> writeWorkoutResult(WorkoutSession session) async {
final json = session.toJsonString();
// Always update the in-app HTTP server so the PC can read via WiFi.
HttpServerService.instance.latestWorkout = json;
// Try the primary path first (/sdcard/ — ADB-accessible without root).
try {
final file = File(kSyncFilePath);
await file.writeAsString(json);
return const SyncResult(success: true, path: kSyncFilePath);
} on Exception {
// Fallback: app-specific external directory (still ADB accessible).
}
// External storage is Android-only; getExternalStorageDirectory() throws an
// UnsupportedError (not an Exception) on other platforms, so guard the call.
if (Platform.isAndroid) {
try {
final dir = await getExternalStorageDirectory();
if (dir != null) {
final file = File('${dir.path}/workout_result.json');
await file.writeAsString(json);
return SyncResult(success: true, path: file.path);
}
} on Exception {
// Fallback failed.
}
}
return const SyncResult(
success: false,
path: null,
error: 'No writable external path',
);
}
}
/// Result of a [SyncService.writeWorkoutResult] call.
class SyncResult {
/// Creates a sync result.
const SyncResult({required this.success, required this.path, this.error});
/// Whether the write succeeded.
final bool success;
/// Absolute path where the file was written, or null on failure.
final String? path;
/// Human-readable error message on failure.
final String? error;
}