지금 개인으로 만든 앱을 여자친구랑 함께 쓰고있다
여기서 mvvm 패턴을 적용한 예시를 적으려고 한다
View
ViewModel
Model
Model.dart
class Event {
String date;
String weather;
String second;
String first;
String secondEmail;
String firstEmail;
String secondMood;
String firstMood;
Timestamp? timestamp;
Event({
required this.date,
required this.weather,
required this.second,
required this.first,
required this.secondEmail,
required this.firstEmail,
required this.secondMood,
required this.firstMood,
required this.timestamp,
});
factory Event.fromDocumentSnapshot(DocumentSnapshot json) {
return Event(
date: json['Date'] == null ? '' : json['Date'] as String,
weather: json['weather'] == null ? '' : json['weather'] as String,
second: json['second'] == null ? '' : json['second'] as String,
first: json['first'] == null ? '' : json['first'] as String,
secondEmail: json['secondEmail'] == null ? '' : json['secondEmail'] as String,
firstEmail: json['firstEmail'] == null ? '' : json['firstEmail'] as String,
secondMood: json['secondMood'] == null ? '' : json['secondMood'] as String,
firstMood: json['firstMood'] == null ? '' : json['firstMood'] as String,
timestamp: json['timestamp'] == null ? null : json['timestamp'] as Timestamp,
);
}
Map<String, dynamic> toJson() => {
'Date': date,
'weather': weather,
'second': second,
'first': first,
'secondEmail': secondEmail,
'firstEmail': firstEmail,
'secondMood': secondMood,
'firstMood': firstMood,
'timestamp': timestamp,
};
}
firebase를 활용하기 때문에 factory에 DocumentSnapsht 버전을 추가했다.
repository
Future<List<Event>> getEventsAll(sort) async {
List<Event> events = [];
var data = await FirebaseFirestore.instance.collection('Calendar').orderBy('timestamp', descending: sort).get();
for (var element in data.docs) {
events.add(Event.fromDocumentSnapshot(element));
}
return events;
}
로
repository에서 api호출을 해 데이터 모델로 저장한다
ViewModel.dart
class EventViewModel extends ChangeNotifier {
final eventRepository = EventRepository();
List<Event> _eventList = [];
List<Event> get eventList => _eventList;
Future<void> getEventAllList(bool sort) async {
_eventList = await eventRepository.getEventsAll(sort);
notifyListeners();
}
}
이렇게 ViewModel에서 reposiotory에 api를 호출한다
View.dart
class CalendarListView extends StatefulWidget {
const CalendarListView({super.key});
@override
State<CalendarListView> createState() => _CalendarListViewState();
}
class _CalendarListViewState extends State<CalendarListView> {
bool sort = false;
List<Event> eventList = [];
@override
Widget build(BuildContext context) {
return Consumer<EventViewModel>(builder: (context, provider, child) { //provider Consumer로 ViewModel 활용
provider.getEventAllList(sort); //api 호출
eventList = provider.eventList; //연결
return Scaffold(
appBar: AppBar(
leading: BackButton(
color: Colors.black,
onPressed: () {
Navigator.pop(context);
},
),
title: const Text(
'날씨 모아보기',
style: TextStyle(fontSize: 16, color: Colors.black),
),
actions: [
IconButton(
onPressed: () async {
setState(() {
sort = !sort;
});
provider.getEventAllList(sort);
},
icon: Icon(sort == false ? Icons.arrow_downward : Icons.arrow_upward),
),
],
elevation: 0,
),
body: buildListView(context, eventList),
);
});
}
Widget buildListView(BuildContext context, List<Event> eventList) {
return eventList.isEmpty
? const Center(
child: Text('값이 없어요 ㅠㅠ'),
)
: ListView.builder(
itemCount: eventList.length,
itemBuilder: (context, index) {
return ExpansionTile(
title: Row(
children: [
Text(
eventList[index].date,
style: const TextStyle(
color: Color(0xFF7D5260),
),
),
const SizedBox(
width: 5,
),
eventList[index].weather != ''
? Image.asset(
'images/${eventList[index].weather}.png',
width: 43,
height: 43,
)
: const SizedBox.shrink()
],
),
children: [
Container(
margin: const EdgeInsets.fromLTRB(5, 15, 5, 15),
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: const Color(0xFFFFD8E4),
),
borderRadius: BorderRadius.circular(12.0),
),
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(eventList[index].first,
style: eventList[index].firstEmail == Provider.of<UserProvider>(context, listen: false).email
? const TextStyle(color: Color(0xFF6750A4))
: const TextStyle(color: Color(0xFF6750A4), fontWeight: FontWeight.bold)),
const SizedBox(
height: 20,
),
eventList[index].second == ''
? const SizedBox.shrink()
: Text(eventList[index].second,
style: eventList[index].secondEmail == Provider.of<UserProvider>(context, listen: false).email
? const TextStyle(color: Color(0xFF6750A4))
: const TextStyle(color: Color(0xFF6750A4), fontWeight: FontWeight.bold)),
],
),
),
],
);
},
);
}
}
이렇게 View -> ViewModel -> repository -> Model순으로 적용되었다
일단 repository는 단순 api를 호출하는 용도로 썼는데 다른 용도가 있을지는 잘 모르겠다..
상태관리로는 Provider를 써보았다
현업에서는 GetX를 쓰고있고 나중에 시간이 난다면 riverpod도 공부해봐야겠다