-
Notifications
You must be signed in to change notification settings - Fork 4
블루베리 템플릿 구현 룰
Jungwoo edited this page Jul 15, 2024
·
1 revision
이 프로젝트는 다음 규칙을 따라 개발되어야 합니다. 이 규칙은 코드의 일관성과 가독성을 높이며, 유지보수를 용이하게 합니다.
- 스크린을 먼저 생성합니다.
- 위젯으로 나눠줍니다. ( 가능하면 StateLess를 사용합니다. )
- 서버와의 통신이 필요한 경우에는 별도의 다트 파일로 생성하고, 프로바이더 또는 서비스를 연결합니다.
- 상단에 설명을 꼭 달아줍니다.
- 먼저 기능이 들어갈 상단의 스크린을 생성합니다.
- 스크린은 StatelessWidget으로 생성합니다. ( 특별한 이유가 없는 한 )
- 위젯 중 프로바이더, 서비스 연결이 필요한 위젯은 별도의 다트 파일로 분리합니다.
- 위젯 중 프로바이더, 서비스 연결이 필요 없는 위젯은 하단에 나열합니다.
class ChatScreen extends StatelessWidget {
const ChatScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text(AppStrings.lessonChatScreenTitle)),
body: Center(
child: Column(
children: [
Expanded(child: ChatListWidget()),
ChatSendWidget(),
],
),
),
);
}
}
- Provider를 사용하는 위젯 ( 데이터를 서버로부터 받아오는 경우 )
- ConsumerWidget으로 감싸고 Provider를 사용합니다.
- build 함수 안에 when문을 사용합니다.
- data, loading, error의 경우에 보여줄 위젯을 하단에 정리합니다.
class ChatListWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final _list = ref.watch(chatListProvider);
return _list.when(
data: (data) => _buildListView(data),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stackTrace) => Center(child: Text('Error: $error')));
}
}
Widget _buildListView(List<String> data) {
return ListView.builder(
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(data[index]),
);
},
);
}
- Provider 구현방법
- Provider내에서 다른 서비스, 다른 프로바이더를 참고하는 것을 금지합니다.
- Firebase Repository, Service가 별도로 존재하더라도 프로바이더에는 새로운 instance를 생성 해야합니다.
final chatListProvider = StreamProvider<List<String>>((ref) {
final firestore = FirebaseFirestore.instance;
return firestore.collection('chats').snapshots().map((snapshot) {
return snapshot.docs.map((doc) => doc['message'] as String).toList();
});
});
- Service를 사용하는 위젯 ( 데이터를 서버로 보내기만 하는 경우 )
- StateLessWidget을 사용합니다.
- build 안에서 Service를 가져와서 사용합니다.
class ChatSendWidget extends StatelessWidget {
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
final firebaseService = FirebaseService();
void _sendChatMessage(String value) async {
await firebaseService.addChatMessage(value);
_controller.clear();
}
return Container(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: const InputDecoration(
hintText: 'Enter message', border: OutlineInputBorder()),
onSubmitted: (value) async { // 엔터키가 눌러졌을때 하는 행동
value.isEmpty
? null
: _sendChatMessage(value);
},
),
),
IconButton(
icon: const Icon(Icons.send),
onPressed: () async { // 눌러졌을때 행동
_controller.text.isEmpty
? null
: _sendChatMessage(_controller.text);
},
),
],
),
);
}
}
- Service 구현방법
- 원하는 Request를 보낼 수 있는 함수를 작성합니다.
- 하나의 Service에 여러 위젯, 여러 스크린에서 사용되는 함수를 추가해도 괜찮습니다.
class FirebaseService {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
// ChatScreen.dart
Future<void> addChatMessage(String message) async {
try {
await _firestore.collection('chats').add({
'message': message,
'timestamp': DateTime.now(),
});
} catch (e) {
print('Error adding message: $e');
throw Exception('Failed to add message');
}
}
}