109 lines
3.8 KiB
Dart
109 lines
3.8 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:get/get.dart';
|
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
|
|
|
import '../models/measure_source_point.dart';
|
|
|
|
class SourcePointFetchResult {
|
|
final List<MeasureSourcePoint> points;
|
|
final bool capped;
|
|
const SourcePointFetchResult({required this.points, required this.capped});
|
|
}
|
|
|
|
/// Forráspontok (jelgerjesztés/tartalék) lekérdezése a navigációs
|
|
/// térképhez. SZÁNDÉKOSAN tisztán online — nincs helyi tükör.
|
|
class MeasureSourcePointService extends GetxService {
|
|
static MeasureSourcePointService get to => Get.find();
|
|
|
|
SupabaseClient get _client => Supabase.instance.client;
|
|
|
|
/// Ha egy pontnak VAN megadott tervezett dátuma, csak a mait mutatjuk;
|
|
/// aminek NINCS dátuma, azt mindig — plusz egy kemény felső korlát,
|
|
/// nehogy egy dátum nélküli projektnél ezerszámra terhelje a térképet.
|
|
static const _safetyLimit = 6000;
|
|
|
|
/// Élő frissítés a stream() helyett: a tényleges adatot SZERVER-oldali
|
|
/// szűréssel, lapozva kérjük le (a PostgREST 1000 soros felső
|
|
/// korlátja miatt a .stream() csonkított, rendezetlen részhalmazt
|
|
/// adott), a realtime csatorna pedig csak jelez, hogy változott
|
|
/// valami — ilyenkor újra lekérünk.
|
|
Stream<SourcePointFetchResult> watchTodayOrUndated(String projectId) {
|
|
late StreamController<SourcePointFetchResult> controller;
|
|
RealtimeChannel? channel;
|
|
Timer? debounce;
|
|
var disposed = false;
|
|
|
|
Future<void> refetch() async {
|
|
if (disposed) return;
|
|
try {
|
|
final result = await _fetchAll(projectId);
|
|
if (!disposed) controller.add(result);
|
|
} catch (e, s) {
|
|
if (!disposed) controller.addError(e, s);
|
|
}
|
|
}
|
|
|
|
controller = StreamController<SourcePointFetchResult>(
|
|
onListen: () {
|
|
refetch();
|
|
channel = _client
|
|
.channel('source_points_$projectId')
|
|
.onPostgresChanges(
|
|
event: PostgresChangeEvent.all,
|
|
schema: 'public',
|
|
table: 'terepi_seged_measure_source_points',
|
|
filter: PostgresChangeFilter(
|
|
type: PostgresChangeFilterType.eq,
|
|
column: 'project_id',
|
|
value: projectId,
|
|
),
|
|
callback: (_) {
|
|
// Sok egyidejű változásnál (pl. tömeges import) ne
|
|
// kérjünk le minden egyes sorra újra.
|
|
debounce?.cancel();
|
|
debounce = Timer(const Duration(milliseconds: 600), refetch);
|
|
},
|
|
)
|
|
.subscribe();
|
|
},
|
|
onCancel: () async {
|
|
disposed = true;
|
|
debounce?.cancel();
|
|
if (channel != null) await _client.removeChannel(channel!);
|
|
},
|
|
);
|
|
return controller.stream;
|
|
}
|
|
|
|
Future<SourcePointFetchResult> _fetchAll(String projectId) async {
|
|
final now = DateTime.now();
|
|
final todayStr = '${now.year.toString().padLeft(4, '0')}-'
|
|
'${now.month.toString().padLeft(2, '0')}-'
|
|
'${now.day.toString().padLeft(2, '0')}';
|
|
|
|
const pageSize = 1000;
|
|
final all = <MeasureSourcePoint>[];
|
|
var from = 0;
|
|
while (all.length <= _safetyLimit) {
|
|
final rows = await _client
|
|
.from('terepi_seged_measure_source_points')
|
|
.select()
|
|
.eq('project_id', projectId)
|
|
.eq('is_active', true)
|
|
.or('planned_acquisition_date.eq.$todayStr,'
|
|
'planned_acquisition_date.is.null')
|
|
.order('line_number', ascending: true)
|
|
.order('point_number', ascending: true)
|
|
.range(from, from + pageSize - 1);
|
|
all.addAll(rows.map((r) => MeasureSourcePoint.fromMap(r)));
|
|
if (rows.length < pageSize) break;
|
|
from += pageSize;
|
|
}
|
|
|
|
final capped = all.length > _safetyLimit;
|
|
if (capped) all.removeRange(_safetyLimit, all.length);
|
|
return SourcePointFetchResult(points: all, capped: capped);
|
|
}
|
|
}
|