[앱개발] 예보 : 마음을 읽다.
[앱개발] 날씨 기록 - firestore 를 활용하여 사용자의 마음의 날씨를 기록한다.
godofwisdom
2022. 4. 8. 18:40
사용자의 현재의 마음의 날씨 상태를 기록 하는 "날씨 기록 페이지" 이다.
폴더구조 설명
presentation
ㄴ weather_write : 화면기록 폴더
ㄴ component : 화면에서 사용하는 위젯
ㄴ view_model : 화면에 대한 event 및 view 모델
ㄴ weather_write_screen.dart : 화면을 그리는 파일
화면에서의 이벤트를 freezed 라이브러리를 사용하여서 정의 한다.
@freezed
class WeatherWriteEvent with _$WeatherWriteEvent {
const factory WeatherWriteEvent.onChangeWeather(String code) =
OnChangeWeather;
const factory WeatherWriteEvent.insertWeather(WeatherModel weatherModel) =
InsertWeather;
const factory WeatherWriteEvent.updateWeather(WeatherModel weatherModel) =
UpdateWeather;
const factory WeatherWriteEvent.deleteWeather(WeatherModel weatherModel) =
DeleteWeather;
factory WeatherWriteEvent.fromJson(Map<String, dynamic> json) =>
_$WeatherWriteEventFromJson(json);
}
이벤트를 ViewModel에서 구현한다.
/// 이벤트의 기능을 구현하는곳
class WeatherWriteViewModel extends ChangeNotifier {
final WeatherRepository weatherRepository;
String _weatherCode = "sun";
String get weathercode => _weatherCode;
//여러번 리슨을 해야하는 경우 broadcast 생성자를 사용해야 오류가나지 않는다.
final _eventcontroller = StreamController<WeatherWriteEvent>.broadcast();
Stream<WeatherWriteEvent> get eventStream => _eventcontroller.stream;
WeatherWriteViewModel(this.weatherRepository);
void onEvent(WeatherWriteEvent event) async {
event.when(
insertWeather: _insertWeather,
updateWeather: _updateWeather,
deleteWeather: _deleteWeather,
onChangeWeather: _onChangeWeather);
}
Future<void> _onChangeWeather(String code) async {
_weatherCode = code;
notifyListeners();
}
Future<void> _insertWeather(WeatherModel weatherModel) async {
await weatherRepository.insertWeather(weatherModel);
}
Future<void> _updateWeather(WeatherModel weatherModel) async {
await weatherRepository.updateWeather(weatherModel);
}
Future<void> _deleteWeather(WeatherModel weatherModel) async {
await weatherRepository.deleteWeather(weatherModel);
}
}
화면에서 유저가 날씨를 클릭할때마다 ViewModel 에서 weatherCode를 관리하여 notifylisteners를 실행 해준다.
String _weatherCode = "sun";
String get weatherCode => _weatherCode;
Future<void> _onChangeWeather(String code) async {
_weatherCode = code;
notifyListeners();
}
화면에서 유저가 저장을 하였을때에는 ViewModel 에서 StreamController를 통하여서 관리를 한다.
//여러번 리슨을 해야하는 경우 broadcast 생성자를 사용해야 오류가나지 않는다.
final _eventcontroller = StreamController<WeatherWriteUiEvent>.broadcast();
Stream<WeatherWriteUiEvent> get eventStream => _eventcontroller.stream;
사용자가 날씨를 저장할 때,
Future<void> _insertWeather(WeatherModel weatherModel) async {
await weatherRepository.insertWeather(weatherModel);
_eventcontroller.add(const WeatherWriteUiEvent.saveWeather());
}
firestore에 저장할 때, Repository에 등록되어 있는 firebase utils을 호출한다.
Future<void> insertWeather(WeatherModel weatherModel) async {
firestore
.collection(collectionName)
.doc()
.set(weatherModel.toJson())
.then((value) => print("weather Added"))
.catchError((error) => print("Failed to add WeatherModel: $error"));
}
Screen에서 initState 에 listen 를 등록하여 저장되면 화면이 닫히면서 이전 Navigator를 통하여서 push를 실행한 곳에 true를 넘겨 준다.
@override
void initState(){
super.initState();
Future.microtask((){
final writeViewModel = context.read<WeatherWriteViewModel>();
_streamSubscription = writeViewModel.eventStream.listen((event) {
log("event.toString() : ${event.toString()}");
event.when(saveWeather: (){
//true 이면 save 하고 뒤로 넘어갔을 때 true 를 넘긴다.
Navigator.pop(context, true);
}, showSnackBar: (String message){
final snackBar = SnackBar(content: Text(message));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
});
});
});
}