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