Contents
1. 만보기 라이브러리 viewmodel 만들기1. 만보기 라이브러리 viewmodel 만들기
step_count_viewmodel.dart
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:pedometer/pedometer.dart';
import '../../../../_core/constants/http.dart';
import '../../activity/viewmodel/walking_detail.viewmodel.dart';
class StepCountState {
final int currentSteps;
final String calories;
final String totalSteps;
StepCountState({required this.currentSteps, required this.calories, required this.totalSteps});
}
class StepCountViewModel extends StateNotifier<StepCountState> {
late StreamSubscription<StepCount> _stepCountStream;
Timer? _timer;
Timer? _midnightTimer;
final read;
StepCountViewModel(this.read)
: super(StepCountState(currentSteps: 0, calories: '0 kcal', totalSteps: '0')) {
initialize();
}
void initialize() {
_loadSteps();
_initializePedometer();
_startTimer();
_resetStepsAtMidnight(); // 자정에 리셋 타이머 시작
}
void _initializePedometer() {
_stepCountStream = Pedometer.stepCountStream.listen(
_onStepCount,
onError: _onStepCountError,
);
}
void _onStepCount(StepCount event) {
int steps = event.steps;
_updateState(steps);
_saveSteps(steps);
}
void _onStepCountError(dynamic error) {
print("Step Count Error: $error");
}
void _saveSteps(int steps) async {
await secureStorage.write(key: 'current_steps', value: steps.toString());
}
Future<void> _loadSteps() async {
String? storedSteps = await secureStorage.read(key: 'current_steps');
int steps = int.tryParse(storedSteps ?? '0') ?? 0;
_updateState(steps);
}
void _startTimer() {
_timer = Timer.periodic(Duration(seconds: 10), (Timer timer) {
_sendCurrentStepsToServer();
});
}
void _sendCurrentStepsToServer() async {
String? stepsString = await secureStorage.read(key: 'current_steps');
int steps = int.tryParse(stepsString ?? '0') ?? 0;
read(WalkingDetailProvider.notifier).sendStepsToServer(steps);
}
Duration _timeUntilMidnight() {
final now = DateTime.now();
final tomorrow = DateTime(now.year, now.month, now.day + 1);
return tomorrow.difference(now);
}
// 자정에 데이터 초기화.
void _resetStepsAtMidnight() {
_midnightTimer = Timer(_timeUntilMidnight(), () async {
state = StepCountState(currentSteps: 0, calories: '0 kcal', totalSteps: '0');
await secureStorage.delete(key: 'current_steps');
_resetStepsAtMidnight();
});
}
void _updateState(int steps) {
state = StepCountState(
currentSteps: steps,
calories: (steps * 0.04).toStringAsFixed(0) + ' kcal', // 칼로리 계산 임의로 함
totalSteps: steps.toString(),
);
}
@override
void dispose() {
_stepCountStream.cancel();
_timer?.cancel();
_midnightTimer?.cancel();
super.dispose();
}
}
final StepCountProvider = StateNotifierProvider<StepCountViewModel, StepCountState>((ref) {
return StepCountViewModel(ref.read);
});
secure storege 라이브러리를 사용해 만보기 데이터를 디바이스에 저장 후 꺼내서 서버로 전송한다. 자정이 되면 secure storege 의 값을 삭제한다.
_sendCurrentStepsToServer
메서드를 통해 서버와 통신한다.walking_detail_viewmodel.dart
Future<void> sendStepsToServer(int steps) async {
await ActivityRepository().fetchSendWalking(steps);
}
인서트만 하기 때문에 따로 응답은 받지 않는다.
activity_repository.dart
Future<ResponseDTO> fetchSendWalking(int steps) async {
StepDTO stepDTO = StepDTO(steps);
final response =
await dio.put("/api/activities/walking-update", data: stepDTO);
ResponseDTO responseDTO = ResponseDTO.fromJson(response.data);
return responseDTO;
}
서버에 데이터를 전송한다.
activity_request.dart
class StepDTO {
int walking;
StepDTO(this.walking);
Map<String, dynamic> toJson() {
return {"walking": this.walking};
}
}
데이터를 담아 서버에 전송한다.

viewmodel 로 만들었기 때문에 consumerWidget만 있으면 어디서든 불러올 수 있다.

Share article