Gemini App에서 사용되는 플러그인
dio
dio는 Dart 및 Flutter 앱에서 HTTP 통신을 보다 쉽고 강력하게 처리할 수 있도록 도와주는 비동기 HTTP 클라이언트 라이브러리입니다.
기능 | 설명 |
GET, POST, PUT, DELETE 지원 | RESTful API에 필요한 모든 메서드 지원 |
인터셉터 (Interceptor) | 요청/응답 전후에 가로채서 처리 가능 (예: 인증 토큰 자동 삽입) |
FormData 업로드 | 파일/폼데이터 업로드에 최적화 (multipart/form-data) |
타임아웃 설정 | 연결, 수신, 요청 타임아웃 각각 설정 가능 |
진행률 표시 | 다운로드/업로드 진행 상황 추적 가능 |
자동 재시도 | 실패한 요청을 자동으로 재시도 (옵션) |
쿠키 관리 | 내장 CookieJar 또는 사용자 지정 Cookie 설정 가능 |
기본 사용법
import 'package:dio/dio.dart';
void fetchData() async {
final dio = Dio(); // Dio 인스턴스 생성
try {
final response = await dio.get('https://api.example.com/data');
print(response.data); // 서버 응답 출력
} catch (e) {
print('요청 실패: $e');
}
}
1. POST 요청 (JSON 또는 FormData)
// JSON 데이터 POST
await dio.post('https://example.com/api',
data: {'name': '홍길동', 'age': 30},
);
// 파일 업로드 (FormData)
final formData = FormData.fromMap({
'name': '홍길동',
'profile': await MultipartFile.fromFile('path/to/image.png'),
});
await dio.post('https://example.com/upload', data: formData);
2. Interceptor 예시 (토큰 자동 추가)
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
options.headers['Authorization'] = 'Bearer YOUR_TOKEN';
return handler.next(options);
},
));
3. 고급 설정 예시
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com/',
connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 3),
headers: {'Accept': 'application/json'},
));
관련 플러그인
플러그인 | 설명 |
dio_http_cache | 응답 캐싱 지원 |
dio_cookie_manager | 쿠키 자동 관리 |
pretty_dio_logger | 콘솔용 요청/응답 로깅 |
Hive
Hive는 Flutter와 Dart 전용의 초고속 키-값(Key-Value) 기반 NoSQL 로컬 데이터베이스입니다.
기능 | 설명 |
빠른 속도 | 네이티브 코드보다 빠르게 동작 (메모리 기반 캐시) |
간단한 구조 | NoSQL 스타일, Box 단위 저장소 |
Flutter 친화적 | Null-safety, 타입 안전, 모바일 최적화 |
지속성 저장 | 기기 로컬에 데이터 영구 저장 |
확장성 | 어댑터를 통해 사용자 정의 클래스도 저장 가능 |
test-friendly | 쉽게 모킹 가능, 단위 테스트에 적합 |
설치
dependencies:
hive: ^2.2.3
hive_flutter: ^1.1.0
flutter pub get
기본 사용법
1. 초기화 및 사용
import 'package:hive_flutter/hive_flutter.dart';
void main() async {
await Hive.initFlutter(); // Flutter용 Hive 초기화
await Hive.openBox<String>('chat_history'); // 문자열 저장용 Box 열기
runApp(const MyApp());
}
- Box: Hive의 핵심 단위
var box = Hive.box<String>('chat_history');
// 쓰기
box.add('Hello, world!');
box.put('latest', 'Hi there!'); // 키 지정도 가능
// 읽기
print(box.getAt(0)); // 인덱스로 가져오기
print(box.get('latest')); // 키로 가져오기
// 삭제
box.deleteAt(0);
box.clear(); // 전체 삭제
2. Hive + Flutter UI 연동
2.1. ValueListenableBuilder로 실시간 UI 연결
ValueListenableBuilder(
valueListenable: Hive.box<String>('chat_history').listenable(),
builder: (context, Box<String> box, _) {
return ListView(
children: box.values.map((v) => Text(v)).toList(),
);
},
);
2.2. 직접 StreamBuilder와 연결 (custom stream)
Stream<List<String>> chatStream(Box<String> box) {
final controller = StreamController<List<String>>();
controller.add(box.values.toList());
box.listenable().addListener(() {
controller.add(box.values.toList());
});
return controller.stream;
}
Hive 사용 추천 앱
앱 종류 | 설명 |
채팅 앱 | 메시지 기록 로컬 저장 |
To-Do 앱 | 할 일 목록 로컬 저장 |
캐시 앱 | JSON API 응답 로컬 캐싱 |
사용자 설정 저장 | 테마, 언어 등 설정 저장 |
google_generative_ai
Google에서 제공하는 Gemini API를 Dart/Flutter에서 직접 사용할 수 있게 해주는 공식 플러그인입니다.
항목 | 내용 |
플러그인 이름 | google_generative_ai |
현재 버전 | ^0.4.7 (2025년 기준 최신) |
목적 | Gemini 모델과 직접 통신 (텍스트 생성, 대화 세션 등) |
제공처 | Google 공식 (Dart용 Gemini SDK) |
사용 가능 모델 | gemini-pro, gemini-2.0-flash, gemini-1.5-pro, 등 |
기본 사용법
1. 모델 초기화
final model = GenerativeModel(
model: 'gemini-2.0-flash',
apiKey: 'YOUR_API_KEY', // 또는 dotenv 사용 가능
);
2. 메시지 보내기
final response = await model.generateContent([
Content.text('Flutter로 앱을 만들고 있어요.')
]);
print(response.text); // 결과 출력
3. ChatSession으로 대화 유지
final chat = model.startChat();
final response = await chat.sendMessage(
Content.text('이전 대화 기억해?'),
);
print(response.text);
- startChat()을 쓰면 대화 문맥이 유지되어 실제 챗봇처럼 작동합니다.
4. Content 생성 방식
Content.text('텍스트만 포함된 메시지');
Content.model('모델 응답으로 저장된 텍스트');
Content.multi([
TextPart('텍스트'),
ImagePart(bytes: imageBytes, mimeType: 'image/png'),
]);
5. 고급 설정
final model = GenerativeModel(
model: 'gemini-2.0-pro',
apiKey: dotenv.env['GEMINI_API_KEY']!,
generationConfig: GenerationConfig(
temperature: 0.9, // 창의성 조절 (0~1)
maxOutputTokens: 1024, // 최대 응답 길이
topK: 40, // 확률 기반 샘플링
topP: 0.95,
),
safetySettings: [
SafetySetting(HarmCategory.harassment, HarmBlockThreshold.low),
],
);
주요 클래스
클래스/함수 | 설명 |
GenerativeModel | Gemini 모델 정의 (버전, 키, 옵션 포함) |
generateContent() | 비동기 응답 생성 (한 번 요청) |
startChat() | 지속적인 대화 세션 생성 |
ChatSession | 대화 상태 추적 객체 |
Content / TextPart | 전송할 메시지 정의용 클래스 |
GenerationConfig | 응답 길이, 창의성 조절 |
SafetySetting | 유해 콘텐츠 필터링 옵션 |
flutter_markdown
Flutter 앱에서 마크다운(Markdown) 형식의 텍스트를 위젯으로 렌더링할 수 있도록 도와주는 플러그인입니다. 이 플러그인을 사용하면 **굵은 글씨**, _기울임_, [링크](https://...), 코드 등 마크다운 문법을 자연스럽게 앱에서 표현할 수 있습니다.
항목 | 설명 |
플러그인 이름 | flutter_markdown |
최신 버전 (2025.04 기준) | ^0.6.18 |
제공 기능 | 마크다운 텍스트 렌더링 (텍스트, 링크, 리스트, 코드, 이미지 등) |
공식 문서 | https://pub.dev/packages/flutter_markdown |
기본 사용법
1. 마크다운 텍스트 렌더링
import 'package:flutter_markdown/flutter_markdown.dart';
MarkdownBody(
data: '**굵은 글씨**, _기울임_, [링크](https://flutter.dev)',
)
또는 스크롤이 가능한 영역에 렌더링하려면:
Markdown(
data: '# 제목\n\n**굵은 텍스트** 와 일반 텍스트를 혼합할 수 있어요.',
)
2. 스타일 커스터마이징
MarkdownBody(
data: '## 제목\n_기울임_ **굵게**',
styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith(
h2: const TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold),
p: const TextStyle(fontSize: 16, height: 1.5),
),
)
3. 링크 자동 열기
MarkdownBody(
data: '[Flutter](https://flutter.dev)',
onTapLink: (text, href, title) {
print('링크 클릭됨: $href');
},
)
4. 이미지 지원
MarkdownBody(
data: '',
)
build_runner
Dart/Flutter 생태계에서 코드 생성(code generation)을 자동화하기 위한 핵심 유틸리티 플러그인입니다.
Dart의 코드 생성 도구(code generator) 실행기를 위한 플러그인입니다. 예를 들어 JSON 직렬화, Hive 어댑터, Freezed 모델 등을 자동 생성할 때 사용됩니다.
주로 함께 쓰는 코드 생성 플러그인들
사용하는 기능 | 함께 사용하는 패키지 |
JSON 직렬화 | json_serializable |
immutable 모델 | freezed |
Hive TypeAdapter | hive_generator |
Drift ORM | drift_dev |
GraphQL 모델 | graphql_codegen |
함께 쓰는 예 (예: Hive):
dependencies:
hive: ^2.2.3
hive_flutter: ^1.1.0
dev_dependencies:
build_runner: ^2.4.6
hive_generator: ^2.0.1
사용 방법
예: HiveAdapter 생성
@HiveType(typeId: 0)
class User {
@HiveField(0)
final String name;
@HiveField(1)
final int age;
User(this.name, this.age);
}
터미널에서 코드 생성
flutter pub run build_runner build
명령어 | 설명 |
build | 처음부터 생성 |
watch | 파일 저장 시 자동 갱신 (핫 리로드처럼) |
clean | 이전 생성된 파일 삭제 |
flutter pub run build_runner watch
Gemini App 만들기
Gemini API Key 발급
APK Key는 Gemini 1.5/2.0 모델과 직접 통신할 수 있도록 해줍니다.
Google Gemini API Key 발급 절차 (2025년 기준)
1.Google AI Studio 접속
- 🔗 링크: https://makersuite.google.com/app/apikey
- Google 계정으로 로그인 (Gmail 등)
로그인 - Google 계정
이메일 또는 휴대전화
accounts.google.com
2. "API Key 만들기" 버튼 클릭
- 로그인 후, 상단 또는 중앙에 있는 [Create API Key] 버튼 클릭
3. 키 이름 지정 및 발급
- 키 이름은 자유롭게 (예: gemini_flutter_dev)
- 생성된 키는 복사하여 안전하게 보관
4. 보안 주의사항
- 절대 키를 코드에 직접 노출하지 마세요 (특히 GitHub 등 공개 저장소)
- .env에 저장하고 dotenv로 불러오기:
GEMINI_API_KEY=AIzaSyA...
await dotenv.load();
final key = dotenv.env['GEMINI_API_KEY'];
App Code
pubspec.yaml
dependencies:
flutter:
sdk: flutter
dio: ^5.8.0+1
flutter_dotenv: ^5.2.1
hive: ^2.2.3
hive_flutter: ^1.1.0
google_generative_ai: ^0.4.7
flutter_markdown: ^0.6.18
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.4.6
hive_generator: ^2.0.0
flutter_launcher_icons: ^0.13.1
flutter_icons:
android: true
ios: false
image_path: "assets/app_icon.png"
flutter:
assets:
- .env
app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 인터넷 권한 -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="Andrew Gemini Chat"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
...
- 네트워크 권한만 추가해주면됩니다.
lib/services/chat_stream.dart
import 'dart:async'; // 비동기 작업과 StreamController 사용을 위한 패키지
import 'package:hive/hive.dart'; // Hive DB 접근을 위한 핵심 패키지
import 'package:hive_flutter/hive_flutter.dart'; // Hive와 Flutter 연동을 위한 패키지
/// 채팅 메시지를 저장한 Hive Box를 감시하고,
/// 변경이 감지될 때마다 최신 메시지 목록(List<String>)을 스트림으로 내보낸다.
Stream<List<String>> chatStream(Box<String> chatBox) {
// Stream을 수동으로 제어할 수 있는 컨트롤러 생성
final controller = StreamController<List<String>>();
// 초기 상태 전송: 현재 Box에 저장된 채팅 메시지 전체를 스트림에 한번 전달
controller.add(chatBox.values.toList());
// 이후 변경 감지 등록
// Box가 listenable하므로 값이 변경될 때마다 알림을 받을 수 있음
chatBox.listenable().addListener(() {
// Box 값이 변경되면 다시 최신 메시지 리스트를 스트림으로 전달
controller.add(chatBox.values.toList());
});
// StreamBuilder 등이 구독할 수 있도록 Stream 반환
return controller.stream;
}
lib/widgets/chat_bubble.dart
import 'package:flutter/material.dart'; // 기본 Flutter UI 위젯 패키지
import 'package:flutter_markdown/flutter_markdown.dart'; // 마크다운 텍스트 렌더링을 위한 패키지
/// 채팅 말풍선을 나타내는 StatelessWidget
/// 메시지가 'You:'로 시작하면 사용자 메시지, 'Gemini:'로 시작하면 봇 응답으로 판단
class ChatBubble extends StatelessWidget {
final String message; // 'You: 안녕' 또는 'Gemini: 안녕하세요' 형태의 문자열
const ChatBubble({
super.key,
required this.message,
});
@override
Widget build(BuildContext context) {
// 메시지가 "You:"로 시작하는지 여부 확인 (사용자 메시지 판단용)
final isUser = message.startsWith("You:");
// "You:" 또는 "Gemini:" 접두사를 제거하여 실제 메시지 내용 추출
final content = message.replaceFirst(RegExp(r'^(You|Gemini):\s*'), '');
// 사용자 메시지면 우측 정렬, 아니면 좌측 정렬
final alignment = isUser ? Alignment.centerRight : Alignment.centerLeft;
// 사용자 메시지면 파란색 계열, 봇 응답이면 회색 계열 배경
final bgColor = isUser ? Colors.blue[100] : Colors.grey[300];
return Align(
alignment: alignment, // 말풍선 정렬
child: Container(
margin: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12.0), // 바깥 여백
padding: const EdgeInsets.all(12.0), // 안쪽 여백
constraints: const BoxConstraints(maxWidth: 280), // 최대 너비 제한
decoration: BoxDecoration(
color: bgColor, // 배경색
borderRadius: BorderRadius.only(
// 둥근 테두리 설정 (말풍선 꼬리 느낌 표현)
topLeft: const Radius.circular(12),
topRight: const Radius.circular(12),
bottomLeft: isUser ? const Radius.circular(12) : Radius.zero,
bottomRight: isUser ? Radius.zero : const Radius.circular(12),
),
),
// 마크다운 문법을 렌더링하는 위젯
child: MarkdownBody(
data: content, // 실제 출력할 메시지 내용
styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith(
p: const TextStyle(fontSize: 16), // 일반 텍스트 스타일 크기 설정
),
),
),
);
}
}
lib/widgets/chat_input_area.dart
import 'package:flutter/material.dart'; // Flutter의 UI 위젯을 위한 핵심 패키지
/// 채팅 입력 영역 위젯
/// - 텍스트 입력 필드와 전송 버튼으로 구성됨
/// - 사용자의 입력을 controller를 통해 관리
/// - 메시지 전송은 onSend 콜백을 통해 처리
class ChatInputArea extends StatelessWidget {
final TextEditingController controller; // 텍스트 입력 필드의 상태를 관리하는 컨트롤러
final VoidCallback onSend; // 전송 버튼 클릭 또는 입력 완료 시 실행될 콜백 함수
const ChatInputArea({
super.key,
required this.controller,
required this.onSend,
});
@override
Widget build(BuildContext context) {
return Padding(
// 위젯 외부 여백 설정 (수평 8, 수직 6)
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6.0),
child: Row(
children: [
// 입력창은 가능한 공간을 모두 차지하도록 확장
Expanded(
child: TextField(
controller: controller, // 입력된 텍스트를 제어하는 컨트롤러
decoration: const InputDecoration(
hintText: "Type a message...", // 입력창 안에 표시될 힌트 텍스트
),
onSubmitted: (_) => onSend(), // 엔터를 눌렀을 때 메시지 전송
),
),
// 전송 버튼 (paper plane 아이콘)
IconButton(
icon: const Icon(Icons.send),
onPressed: onSend, // 클릭 시 메시지 전송 콜백 실행
),
],
),
);
}
}
lib/widgets/chat_message_list.dart
import 'package:flutter/material.dart'; // 기본 위젯 라이브러리
import 'package:hive/hive.dart'; // Hive DB를 사용하기 위한 패키지
import 'package:andrew_chat_gpt/services/chat_stream.dart'; // 채팅 스트림 함수
import 'chat_bubble.dart'; // 각 메시지를 표현하는 말풍선 위젯
/// 실시간 채팅 메시지 목록을 보여주는 위젯
/// - Hive Box로부터 실시간 메시지를 감지하여 표시
/// - 메시지 업데이트 시 자동 스크롤 처리 지원
class ChatMessageList extends StatelessWidget {
final Box<String> chatBox; // 채팅 메시지를 저장한 Hive 박스
final ScrollController scrollController; // 자동 스크롤 처리를 위한 컨트롤러
final VoidCallback onMessagesUpdated; // 새 메시지 등장 시 실행할 콜백 (예: 스크롤)
const ChatMessageList({
super.key,
required this.chatBox,
required this.scrollController,
required this.onMessagesUpdated,
});
@override
Widget build(BuildContext context) {
return StreamBuilder<List<String>>(
stream: chatStream(chatBox), // Hive Box의 변경을 감지하는 스트림
builder: (context, snapshot) {
// snapshot에 데이터가 있으면 채팅 목록으로 가져오고, 없으면 빈 리스트
final chats = snapshot.data ?? [];
// 새 데이터가 들어오면 지정된 콜백 실행 (ex. 스크롤 아래로)
if (snapshot.hasData) onMessagesUpdated();
// 채팅 메시지 리스트 출력
return ListView.builder(
controller: scrollController, // 외부에서 전달받은 스크롤 컨트롤러로 스크롤 위치 조작
itemCount: chats.length, // 채팅 수 만큼 아이템 생성
itemBuilder: (_, index) => ChatBubble(message: chats[index]), // 각 메시지는 ChatBubble 위젯으로 표시
);
},
);
}
}
lib/screen/chat_screen.dart
import 'package:flutter/material.dart'; // 기본 Flutter UI 패키지
import 'package:flutter_dotenv/flutter_dotenv.dart'; // .env 환경변수 사용
import 'package:google_generative_ai/google_generative_ai.dart'; // Gemini API 사용
import 'package:hive/hive.dart'; // Hive DB 사용
import '../widgets/chat_input_area.dart'; // 입력창 위젯
import '../widgets/chat_message_list.dart'; // 채팅 목록 위젯
/// 메인 채팅 화면 - Gemini API와 연동되어 대화를 처리하는 StatefulWidget
class ChatScreen extends StatefulWidget {
const ChatScreen({super.key});
@override
State<ChatScreen> createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
// 텍스트 입력 필드용 컨트롤러
late final TextEditingController _controller;
// 자동 스크롤을 위한 컨트롤러
late final ScrollController _scrollController;
// Hive 저장소에서 불러온 채팅 박스
late final Box<String> _chatBox;
// Gemini 모델 객체
late final GenerativeModel _model;
// Gemini와의 세션 (대화 컨텍스트 포함)
late ChatSession _chatSession;
@override
void initState() {
super.initState();
_controller = TextEditingController();
_scrollController = ScrollController();
_chatBox = Hive.box<String>('chat_history');
_initializeChatSession(); // 모델 초기화 및 세션 설정
}
/// Gemini 모델 생성 및 대화 세션 초기화
void _initializeChatSession() {
_model = GenerativeModel(
model: 'gemini-2.0-flash',
apiKey: dotenv.env['GEMINI_API_KEY']!, // .env에서 API 키 로드
);
_chatSession = _model.startChat(); // 새로운 대화 세션 시작
_restoreSessionFromDB(); // DB에서 이전 대화 내역 복원
}
/// Hive에 저장된 메시지 내역을 기반으로 Gemini 세션에 재전송
void _restoreSessionFromDB() {
final messages = _chatBox.values.toList();
for (final msg in messages) {
if (msg.startsWith("You:")) {
final text = msg.replaceFirst("You:", "").trim();
_chatSession.sendMessage(Content.text(text)); // 사용자 메시지 복원
} else if (msg.startsWith("Gemini:")) {
final text = msg.replaceFirst("Gemini:", "").trim();
_chatSession.sendMessageStream(Content.text(text)); // Gemini 응답 복원
}
}
}
/// 입력한 메시지를 Gemini API에 전송하고, 응답을 DB에 저장
Future<void> _sendMessage() async {
final input = _controller.text.trim();
if (input.isEmpty) return;
final userMessage = 'You: $input';
_chatBox.add(userMessage); // 입력 메시지 DB 저장
_controller.clear(); // 입력 필드 초기화
try {
final response = await _chatSession.sendMessage(Content.text(input));
final reply = 'Gemini: ${response.text ?? "No response."}';
_chatBox.add(reply); // Gemini 응답 저장
} catch (e) {
final error = 'Gemini: Error - $e';
_chatBox.add(error); // 에러 메시지 저장
}
}
/// 새 메시지가 추가되었을 때 자동 스크롤 처리
void _scrollToBottom() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
});
}
/// 새 채팅 시작: 기존 메시지 삭제 및 새 세션 시작
Future<void> _startNewChat() async {
await _chatBox.clear(); // DB 초기화
setState(() {
_chatSession = _model.startChat(); // 세션 초기화
});
}
@override
void dispose() {
_controller.dispose();
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Gemini Chat")), // 앱 상단 제목 바
body: Stack(
children: [
Column(
children: [
// 채팅 메시지 목록
Expanded(
child: ChatMessageList(
chatBox: _chatBox,
scrollController: _scrollController,
onMessagesUpdated: _scrollToBottom,
),
),
const Divider(height: 1), // 구분선
// 입력창 영역
ChatInputArea(
controller: _controller,
onSend: _sendMessage,
),
],
),
// 우측 하단 새 채팅 버튼 (FAB)
Positioned(
bottom: 100,
right: 16,
child: FloatingActionButton.small(
onPressed: _startNewChat,
tooltip: '새 채팅',
child: const Icon(Icons.refresh),
),
),
],
),
);
}
}
lib/main.dart
import 'package:andrew_chat_gpt/screen/chat_screen.dart'; // 메인 채팅 화면 위젯
import 'package:flutter/material.dart'; // Flutter UI 위젯의 핵심 패키지
import 'package:flutter_dotenv/flutter_dotenv.dart'; // .env 환경변수 로드용 패키지
import 'package:hive_flutter/hive_flutter.dart'; // Hive와 Flutter 연동을 위한 패키지
/// 앱 실행 진입점
void main() async {
// Flutter에서 비동기 초기화를 위해 필요한 준비 작업 (runApp 전에)
WidgetsFlutterBinding.ensureInitialized();
// .env 파일 로딩 (.env 파일에서 API KEY 등 비밀 정보 읽기)
await dotenv.load();
// Hive DB 초기화 (Flutter 앱 환경에 맞게 설정)
await Hive.initFlutter();
// 채팅 기록을 저장할 박스 오픈 (문자열 형태로 저장)
await Hive.openBox<String>('chat_history');
// 앱 실행
runApp(const GeminiApp());
}
/// 전체 애플리케이션을 감싸는 루트 위젯
class GeminiApp extends StatelessWidget {
const GeminiApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Gemini Chat', // 앱 타이틀 (시스템 상에서 보일 수 있음)
theme: ThemeData(
primarySwatch: Colors.indigo, // 앱 전체 테마 색상 설정
),
home: const ChatScreen(), // 첫 화면으로 ChatScreen 지정
debugShowCheckedModeBanner: false, // 우측 상단 디버그 배너 숨김
);
}
}
'Flutter for Beginners' 카테고리의 다른 글
Flutter 게시판 with Hive (0) | 2025.04.23 |
---|---|
Flutter 포토 스티커 (0) | 2025.04.21 |
Flutter Google Map (0) | 2025.04.18 |
Flutter 영상통화 (0) | 2025.04.15 |
Flutter 비디오 플레이어 (0) | 2025.04.10 |