크기 1차 수정

This commit is contained in:
2026-06-26 15:14:58 +09:00
parent 8ea5c911e7
commit c0fb4d02d5
5 changed files with 167 additions and 110 deletions

View File

@@ -5,6 +5,22 @@ import '../services/chat_service.dart';
import 'dart:math';
// ===== 반응형 크기 계산 함수 =====
double _getResponsiveFontSize(BuildContext context, double baseSize) {
double screenWidth = MediaQuery.of(context).size.width;
return baseSize * (screenWidth / 1366); // 기준: 1366px (14.1인치)
}
double _getResponsivePadding(BuildContext context, double basePadding) {
double screenWidth = MediaQuery.of(context).size.width;
return basePadding * (screenWidth / 1366);
}
double _getResponsiveSize(BuildContext context, double baseSize) {
double screenWidth = MediaQuery.of(context).size.width;
return baseSize * (screenWidth / 1366);
}
class ChatScreen extends StatefulWidget {
const ChatScreen({Key? key}) : super(key: key);
@@ -224,7 +240,7 @@ class _ChatScreenState extends State<ChatScreen> {
),
child: Center(
child: Container(
margin: const EdgeInsets.all(30), // 메인 컨테이너 여백 조정
margin: EdgeInsets.all(_getResponsivePadding(context, 30)), // 메인 컨테이너 여백 조정
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.8), // 투명도 넣기
borderRadius: BorderRadius.circular(36), // 모서리 둥글게
@@ -235,37 +251,47 @@ class _ChatScreenState extends State<ChatScreen> {
Expanded(
flex: 5,
child: Container(
margin: const EdgeInsets.fromLTRB(30, 0, 30, 50),
margin: EdgeInsets.fromLTRB(
_getResponsivePadding(context, 30),
_getResponsivePadding(context, 50),
_getResponsivePadding(context, 30),
_getResponsivePadding(context, 50),
),
child: Column(
children: [
// 헤더
Padding(
padding: const EdgeInsets.fromLTRB(30, 66, 30, 30),
padding: EdgeInsets.fromLTRB(
_getResponsivePadding(context, 30),
_getResponsivePadding(context, 20),
_getResponsivePadding(context, 30),
_getResponsivePadding(context, 15),
),
child: Row(
children: [
Container(
width: 44,
height: 44,
width: _getResponsiveSize(context, 44),
height: _getResponsiveSize(context, 44),
decoration: BoxDecoration(
color: Color(0xFFC8E6C9),
borderRadius: BorderRadius.circular(12),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 12)),
),
child: const Center(
child: Center(
child: Text(
'🌱',
style: TextStyle(fontSize: 28),
style: TextStyle(fontSize: _getResponsiveFontSize(context, 28)),
),
),
),
const SizedBox(width: 16),
SizedBox(width: _getResponsivePadding(context, 16)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Text(
Text(
'Smart Garden',
style: TextStyle(
fontSize: 20,
fontSize: _getResponsiveFontSize(context, 20),
fontWeight: FontWeight.w600,
color: Color(0xFF212121),
),
@@ -273,7 +299,7 @@ class _ChatScreenState extends State<ChatScreen> {
Text(
'스마트가든 챗봇',
style: TextStyle(
fontSize: 16,
fontSize: _getResponsiveFontSize(context, 16),
color: Color(0xFF757575),
),
),
@@ -285,8 +311,11 @@ class _ChatScreenState extends State<ChatScreen> {
// 캐릭터 영역
Expanded(
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 30,
margin: EdgeInsets.fromLTRB(
_getResponsivePadding(context, 30),
_getResponsivePadding(context, 10),
_getResponsivePadding(context, 30),
_getResponsivePadding(context, 10),
),
decoration: BoxDecoration(
color: Color(0xFFF5F5F5),
@@ -325,7 +354,7 @@ class _ChatScreenState extends State<ChatScreen> {
width: 1,
),
),
child: const Center(
child: Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
@@ -333,11 +362,11 @@ class _ChatScreenState extends State<ChatScreen> {
CircularProgressIndicator(
color: Color(0xFF81C784),
),
SizedBox(height: 20),
SizedBox(height: _getResponsivePadding(context, 20)),
Text(
'비디오 로딩 중...',
style: TextStyle(
fontSize: 12,
fontSize: _getResponsiveFontSize(context, 12),
color: Color(0xFF757575),
),
),
@@ -349,12 +378,18 @@ class _ChatScreenState extends State<ChatScreen> {
),
),
),
const SizedBox(height: 55),
SizedBox(height: _getResponsivePadding(context, 16)),
// SizedBox(height: _getResponsivePadding(context, 16)), //26.06.26
// 캐릭터 정보 + 설명 문구
// 1. 가장 바깥쪽 박스 추가
Container(
margin: const EdgeInsets.fromLTRB(30, 0, 30, 0),
padding: const EdgeInsets.all(24),
margin: EdgeInsets.fromLTRB(
_getResponsivePadding(context, 30),
0,
_getResponsivePadding(context, 30),
0,
),
padding: EdgeInsets.all(_getResponsivePadding(context, 24)),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
borderRadius: BorderRadius.circular(30),
@@ -384,24 +419,24 @@ class _ChatScreenState extends State<ChatScreen> {
child: Image.asset('assets/images/profile.png', fit: BoxFit.cover),
),
),
const SizedBox(width: 12),
const Column(
SizedBox(width: _getResponsivePadding(context, 12)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('푸미', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600, color: Color(0xFF212121))),
Text('스마트가든 AI 가이드', style: TextStyle(fontSize: 14, color: Color(0xFF757575))),
Text('푸미', style: TextStyle(fontSize: _getResponsiveFontSize(context, 18), fontWeight: FontWeight.w600, color: Color(0xFF212121))),
Text('스마트가든 AI 가이드', style: TextStyle(fontSize: _getResponsiveFontSize(context, 14), color: Color(0xFF757575))),
],
),
],
),
const SizedBox(height: 20),
SizedBox(height: _getResponsivePadding(context, 20)),
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
padding: EdgeInsets.all(_getResponsivePadding(context, 16)),
decoration: BoxDecoration(
color: const Color(0xFFF1F8E9),
borderRadius: BorderRadius.circular(12),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 12)),
//border: Border.all(color: const Color(0xFFC8E6C9), width: 1),
boxShadow: [
BoxShadow(
@@ -411,9 +446,9 @@ class _ChatScreenState extends State<ChatScreen> {
),
],
),
child: const Text(
child: Text(
'안녕하세요!\n스마트가든의 식물들이 건강하게 자랄 수 있도록 도와드릴게요.\n궁금한 점을 언제든 물어보세요!',
style: TextStyle(fontSize: 14, color: Colors.black, height: 1.6),
style: TextStyle(fontSize: _getResponsiveFontSize(context, 13), color: Color(0xFF558B2F), height: 1.6),
),
),
],
@@ -427,15 +462,15 @@ class _ChatScreenState extends State<ChatScreen> {
Expanded(
flex: 5,
child: Container(
margin: const EdgeInsets.only(
top: 50,
bottom: 50,
right: 50,
left: 10,
margin: EdgeInsets.only(
top: _getResponsivePadding(context, 50),
bottom: _getResponsivePadding(context, 50),
right: _getResponsivePadding(context, 50),
left: _getResponsivePadding(context, 10),
),
decoration: BoxDecoration(
color: Color(0xFFfbfdf8),
borderRadius: BorderRadius.circular(30),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 30)),
// border: Border.all(
// color: Color(0xFFE0E0E0),
// width: 1,
@@ -452,20 +487,20 @@ class _ChatScreenState extends State<ChatScreen> {
children: [
// 헤더
Container(
padding: const EdgeInsets.all(20),
padding: EdgeInsets.all(_getResponsivePadding(context, 20)),
decoration: BoxDecoration(),
child: Row(
children: [
const Icon(
Icon(
Icons.eco,
color: Color(0xFF81C784),
size: 24,
size: _getResponsiveSize(context, 24),
),
const SizedBox(width: 12),
const Text(
SizedBox(width: _getResponsivePadding(context, 12)),
Text(
'푸미 일지',
style: TextStyle(
fontSize: 22,
fontSize: _getResponsiveFontSize(context, 22),
fontWeight: FontWeight.w600,
color: Color(0xFF212121),
),
@@ -477,8 +512,8 @@ class _ChatScreenState extends State<ChatScreen> {
// 채팅 메시지 영역
Expanded(
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 16,
margin: EdgeInsets.symmetric(
horizontal: _getResponsivePadding(context, 16),
),
// decoration: BoxDecoration(
// image: DecorationImage(
@@ -532,7 +567,7 @@ class _ChatScreenState extends State<ChatScreen> {
),
child: ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(16),
padding: EdgeInsets.all(_getResponsivePadding(context, 16)),
itemCount: _messages.length,
itemBuilder: (context, index) {
final message = _messages[index];
@@ -549,11 +584,19 @@ class _ChatScreenState extends State<ChatScreen> {
),
// 자주하는 질문 버튼들을 감싸는 컨테이너
Container(
margin: const EdgeInsets.fromLTRB(16, 12, 16, 12),
padding: const EdgeInsets.all(12),
margin: EdgeInsets.fromLTRB(
_getResponsivePadding(context, 16),
_getResponsivePadding(context, 12),
_getResponsivePadding(context, 16),
_getResponsivePadding(context, 12),
),
padding: EdgeInsets.symmetric(
horizontal: _getResponsivePadding(context, 6),
vertical: _getResponsivePadding(context, 12),
),
decoration: BoxDecoration(
color: Color(0xFFecf6df).withOpacity(0.8), // 배경
borderRadius: BorderRadius.circular(22),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 22)),
),
child: Row(
children: [
@@ -562,7 +605,7 @@ class _ChatScreenState extends State<ChatScreen> {
child: Container(
decoration: BoxDecoration(
color: Colors.white, // ← 흰색
borderRadius: BorderRadius.circular(25),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 25)),
),
child: Material(
@@ -571,39 +614,39 @@ class _ChatScreenState extends State<ChatScreen> {
onTap: () =>
_sendQuickQuestion('현재 온도는?'),
borderRadius: BorderRadius.circular(
25,
_getResponsiveSize(context, 25),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 12,
padding: EdgeInsets.symmetric(
horizontal: _getResponsivePadding(context, 12),
vertical: _getResponsivePadding(context, 12),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Container(
width: 32,
height: 32,
width: _getResponsiveSize(context, 32),
height: _getResponsiveSize(context, 32),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
6,
_getResponsiveSize(context, 6),
),
),
child: const Center(
child: Center(
child: Icon(
Icons.thermostat,
color: Color(0xFF4CAF50),
size: 25,
size: _getResponsiveSize(context, 25),
),
),
),
const SizedBox(width: 8),
SizedBox(width: _getResponsivePadding(context, 8)),
Text(
'온도 정보',
style: TextStyle(
fontSize: 18,
fontSize: _getResponsiveFontSize(context, 18),
fontWeight: FontWeight.w600,
color: Colors.black,
),
@@ -615,13 +658,13 @@ class _ChatScreenState extends State<ChatScreen> {
),
),
),
const SizedBox(width: 8),
SizedBox(width: _getResponsivePadding(context, 8)),
// 습도 정보
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white, // ← 흰색
borderRadius: BorderRadius.circular(25),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 25)),
),
child: Material(
@@ -630,39 +673,39 @@ class _ChatScreenState extends State<ChatScreen> {
onTap: () =>
_sendQuickQuestion('현재 습도는?'),
borderRadius: BorderRadius.circular(
25,
_getResponsiveSize(context, 25),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 12,
padding: EdgeInsets.symmetric(
horizontal: _getResponsivePadding(context, 12),
vertical: _getResponsivePadding(context, 12),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Container(
width: 32,
height: 32,
width: _getResponsiveSize(context, 32),
height: _getResponsiveSize(context, 32),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
6,
_getResponsiveSize(context, 6),
),
),
child: const Center(
child: Center(
child: Icon(
Icons.water_drop,
color: Color(0xFF4CAF50),
size: 25,
size: _getResponsiveSize(context, 25),
),
),
),
const SizedBox(width: 8),
SizedBox(width: _getResponsivePadding(context, 8)),
Text(
'습도 정보',
style: TextStyle(
fontSize: 18,
fontSize: _getResponsiveFontSize(context, 18),
fontWeight: FontWeight.w600,
color: Color(0xFF000000),
),
@@ -674,13 +717,13 @@ class _ChatScreenState extends State<ChatScreen> {
),
),
),
const SizedBox(width: 8),
SizedBox(width: _getResponsivePadding(context, 8)),
// 물 주기
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white, // ← 흰색
borderRadius: BorderRadius.circular(25),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 25)),
),
child: Material(
color: Colors.transparent,
@@ -688,39 +731,39 @@ class _ChatScreenState extends State<ChatScreen> {
onTap: () =>
_sendQuickQuestion('물을 주세요'),
borderRadius: BorderRadius.circular(
25,
_getResponsiveSize(context, 25),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 12,
padding: EdgeInsets.symmetric(
horizontal: _getResponsivePadding(context, 12),
vertical: _getResponsivePadding(context, 12),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Container(
width: 32,
height: 32,
width: _getResponsiveSize(context, 32),
height: _getResponsiveSize(context, 32),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
6,
_getResponsiveSize(context, 6),
),
),
child: const Center(
child: Center(
child: Icon(
Icons.waves,
color: Color(0xFF4CAF50),
size: 25,
size: _getResponsiveSize(context, 25),
),
),
),
const SizedBox(width: 8),
SizedBox(width: _getResponsivePadding(context, 8)),
Text(
'물 주기',
style: TextStyle(
fontSize: 18,
fontSize: _getResponsiveFontSize(context, 18),
fontWeight: FontWeight.w600,
color: Color(0xFF000000),
),
@@ -737,7 +780,12 @@ class _ChatScreenState extends State<ChatScreen> {
),
// 입력 필드 + 전송 버튼 (같은 줄)
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
padding: EdgeInsets.fromLTRB(
_getResponsivePadding(context, 16),
0,
_getResponsivePadding(context, 16),
_getResponsivePadding(context, 16),
),
child: Row(
children: [
// 입력 필드
@@ -745,7 +793,7 @@ class _ChatScreenState extends State<ChatScreen> {
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(22),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 22)),
// border: Border.all(
// color: Color(0xFFE0E0E0),
// width: 0.5,
@@ -768,26 +816,26 @@ class _ChatScreenState extends State<ChatScreen> {
decoration: InputDecoration(
hintText: '메시지를 입력하세요...',
hintStyle: TextStyle(
fontSize: 16,
fontSize: _getResponsiveFontSize(context, 16),
color: Color(0xFF9E9E9E),
),
border: InputBorder.none,
contentPadding:
const EdgeInsets.symmetric(
horizontal: 16,
vertical: 22,
EdgeInsets.symmetric(
horizontal: _getResponsivePadding(context, 16),
vertical: _getResponsivePadding(context, 22),
),
),
style: const TextStyle(fontSize: 20),
style: TextStyle(fontSize: _getResponsiveFontSize(context, 20)),
maxLines: 1,
),
),
),
const SizedBox(width: 12),
SizedBox(width: _getResponsivePadding(context, 12)),
// 전송 버튼
SizedBox(
height: 60,
width: 60,
height: _getResponsiveSize(context, 60),
width: _getResponsiveSize(context, 60),
child: ElevatedButton(
onPressed: () => _sendMessage(_textController.text),
style: ElevatedButton.styleFrom(
@@ -795,14 +843,14 @@ class _ChatScreenState extends State<ChatScreen> {
elevation: 6, // 그림자 깊이
shadowColor: Colors.black.withOpacity(0.4), // 그림자 색상
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 100)),
),
padding: EdgeInsets.zero,
),
child: ImageIcon(
AssetImage('assets/images/send.png'),
color: Colors.white,
size: 28,
size: _getResponsiveSize(context, 28),
),
),
),
@@ -854,7 +902,9 @@ class _ChatBubble extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 30),
padding: EdgeInsets.only(
bottom: _getResponsivePadding(context, 30),
),
child: Row(
mainAxisAlignment: message.isUser
? MainAxisAlignment.end
@@ -876,7 +926,7 @@ class _ChatBubble extends StatelessWidget {
),
),
),
const SizedBox(width: 10),
SizedBox(width: _getResponsivePadding(context, 10)),
],
Flexible(
child: Row(
@@ -888,20 +938,23 @@ class _ChatBubble extends StatelessWidget {
if (message.isUser)
Text(
_formatTime(message.timestamp),
style: TextStyle(fontSize: 12, color: Color(0xFF9E9E9E)),
style: TextStyle(
fontSize: _getResponsiveFontSize(context, 12),
color: Color(0xFF9E9E9E),
),
),
if (message.isUser) const SizedBox(width: 8),
if (message.isUser) SizedBox(width: _getResponsivePadding(context, 8)),
Flexible(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
padding: EdgeInsets.symmetric(
horizontal: _getResponsivePadding(context, 16),
vertical: _getResponsivePadding(context, 10),
),
decoration: BoxDecoration(
color: message.isUser
? Color(0xFFecf6df)
: Colors.white,
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(_getResponsiveSize(context, 8)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
@@ -915,7 +968,7 @@ class _ChatBubble extends StatelessWidget {
: SelectableText(
message.text,
style: TextStyle(
fontSize: 20,
fontSize: _getResponsiveFontSize(context, 20),
color: message.isUser
? Color(0xFF000000)
: Color(0xFF424242),
@@ -924,11 +977,14 @@ class _ChatBubble extends StatelessWidget {
),
),
),
if (!message.isUser) const SizedBox(width: 8),
if (!message.isUser) SizedBox(width: _getResponsivePadding(context, 8)),
if (!message.isUser)
Text(
_formatTime(message.timestamp),
style: TextStyle(fontSize: 12, color: Color(0xFF9E9E9E)),
style: TextStyle(
fontSize: _getResponsiveFontSize(context, 12),
color: Color(0xFF9E9E9E),
),
),
],
),
@@ -990,13 +1046,13 @@ class _LoadingAnimationState extends State<_LoadingAnimation>
index: 0,
getOffset: _getOffset,
),
const SizedBox(width: 3),
SizedBox(width: _getResponsiveSize(context, 3)),
_AnimatedDot(
progress: progress,
index: 1,
getOffset: _getOffset,
),
const SizedBox(width: 3),
SizedBox(width: _getResponsiveSize(context, 3)),
_AnimatedDot(
progress: progress,
index: 2,