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
