- Position history with polyline trail and date range picker - Map style selector (standard, voyager, light, dark, satellite) persisted via SharedPreferences - Geofence and frequent place CRUD with info cards - Device banner with swipeable carousel - Refresh position button - Widget extraction: map controls, info cards, device banner, modal overlay
46 lines
1.1 KiB
Dart
46 lines
1.1 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:dio/dio.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:sf_infrastructure/sf_infrastructure.dart';
|
|
|
|
class LegacyHeartbeatService {
|
|
LegacyHeartbeatService({
|
|
required QuestiaRepository repository,
|
|
required void Function() onUnauthorized,
|
|
}) : _repository = repository,
|
|
_onUnauthorized = onUnauthorized;
|
|
|
|
final QuestiaRepository _repository;
|
|
final void Function() _onUnauthorized;
|
|
Timer? _timer;
|
|
|
|
static const _interval = Duration(minutes: 3);
|
|
|
|
void start() {
|
|
if (_timer != null) return;
|
|
_beat();
|
|
_timer = Timer.periodic(_interval, (_) => _beat());
|
|
debugPrint('[LegacyHeartbeat] started');
|
|
}
|
|
|
|
void stop() {
|
|
_timer?.cancel();
|
|
_timer = null;
|
|
debugPrint('[LegacyHeartbeat] stopped');
|
|
}
|
|
|
|
Future<void> _beat() async {
|
|
try {
|
|
await _repository.get<dynamic>('/auth/me');
|
|
debugPrint('[LegacyHeartbeat] /auth/me => OK');
|
|
} catch (e) {
|
|
debugPrint('[LegacyHeartbeat] error: $e');
|
|
if (e is DioException && e.response?.statusCode == 401) {
|
|
stop();
|
|
_onUnauthorized();
|
|
}
|
|
}
|
|
}
|
|
}
|