first commit

This commit is contained in:
2026-06-15 18:12:31 +09:00
commit 319cabe9f8
148 changed files with 6242 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
import 'dart:async';
import 'dart:math';
/// 📌 [독립 함수] 지난 24시간 치의 가상(더미) 온도 데이터 리스트를 생성한다.
///
/// 실제 DB 연동 전, 개발 단계에서 차트/리스트 UI를 채우기 위한 용도입니다.
/// 값이 들쭉날쭉 튀지 않고 자연스럽게 보이도록, 직전 값에서 조금씩만
/// 변하는 "랜덤 워크(random walk)" 방식으로 만듭니다.
///
/// - [count] : 만들 데이터 개수 (기본 24개 = 1시간 간격 24시간)
/// - [minTemp] : 가상 온도 하한
/// - [maxTemp] : 가상 온도 상한
List<double> generateDummyTemperatures({
int count = 24,
double minTemp = 18.0,
double maxTemp = 28.0,
}) {
final random = Random();
final list = <double>[];
// 시작 온도는 범위 내 임의 값
double last = minTemp + random.nextDouble() * (maxTemp - minTemp);
for (int i = 0; i < count; i++) {
// 직전 값에서 -0.5 ~ +0.5°C 내외로 흔들기 (clamp는 num 반환 → toDouble)
last = (last + (random.nextDouble() - 0.5)).clamp(minTemp, maxTemp).toDouble();
list.add(double.parse(last.toStringAsFixed(1))); // 소수점 1자리로 정리
}
return list;
}
/// 📡 [스트림 서비스] 앱이 켜져 있는 동안 일정 주기마다
/// 새로운 가상 온도 데이터를 계속 추가하며 갱신된 리스트를 흘려보낸다.
///
/// 사용 흐름:
/// final service = TempDataService()..start();
/// service.stream.listen((temps) { ... }); // StreamBuilder로 구독
/// service.dispose(); // 화면이 사라질 때 반드시 호출
///
/// 👉 나중에 실제 DB 연동 시에는 [_generateNextTemperature] 내부만
/// "DB에서 최신 온도 1건 조회" 로직으로 교체하면 됩니다.
class TempDataService {
TempDataService({
this.minTemp = 18.0,
this.maxTemp = 28.0,
this.historyCount = 24,
this.interval = const Duration(seconds: 3), // ⏱️ 테스트용 3초
this.maxLength = 200, // 메모리 무한 증가 방지용 보관 한도
});
final double minTemp; // 최저 가상 온도
final double maxTemp; // 최고 가상 온도
final int historyCount; // 시작 시 채워둘 24시간 데이터 개수
final Duration interval; // 새 데이터 추가 주기
final int maxLength; // 리스트에 보관할 최대 개수
final _random = Random();
final List<double> _temperatures = [];
Timer? _timer;
// broadcast: 여러 위젯이 동시에 구독할 수 있게 함
final _controller = StreamController<List<double>>.broadcast();
/// 갱신될 때마다 "전체 온도 리스트"가 흘러나오는 스트림
Stream<List<double>> get stream => _controller.stream;
/// 현재까지 쌓인 데이터 (읽기 전용 복사본)
List<double> get current => List.unmodifiable(_temperatures);
/// 스트림 시작: 24시간 더미 데이터로 시드한 뒤, [interval]마다 새 값 추가
void start() {
_temperatures
..clear()
..addAll(generateDummyTemperatures(
count: historyCount,
minTemp: minTemp,
maxTemp: maxTemp,
));
_controller.add(current); // 초기 데이터를 즉시 한 번 전달
_timer?.cancel();
_timer = Timer.periodic(interval, (_) {
_temperatures.add(_generateNextTemperature());
// 오래된 데이터부터 버려서 길이 유지
while (_temperatures.length > maxLength) {
_temperatures.removeAt(0);
}
_controller.add(current);
});
}
/// 다음(새) 가상 온도 한 건을 생성한다. 직전 값 기준 랜덤 워크.
double _generateNextTemperature() {
final last = _temperatures.isEmpty
? minTemp + _random.nextDouble() * (maxTemp - minTemp)
: _temperatures.last;
final next = (last + (_random.nextDouble() - 0.5)).clamp(minTemp, maxTemp);
return double.parse(next.toStringAsFixed(1));
}
/// 타이머 정지 + 스트림 정리. 위젯 dispose() 에서 꼭 호출할 것.
void dispose() {
_timer?.cancel();
_controller.close();
}
}