rup-project/app/lib/widgets/home/pet_profile_card.dart

423 lines
15 KiB
Dart

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:intl/intl.dart';
import '../../models/pet_model.dart';
import '../../screens/pet_form_screen.dart';
class PetProfileCard extends StatelessWidget {
final Pet pet;
final VoidCallback? onPetUpdated;
const PetProfileCard({super.key, required this.pet, this.onPetUpdated});
// 나이 계산 (만 나이 & 사람 나이 환산 - 단순 예시)
String _calculateAge(DateTime? birthDate) {
if (birthDate == null) return '??살';
final now = DateTime.now();
int age = now.year - birthDate.year;
if (now.month < birthDate.month ||
(now.month == birthDate.month && now.day < birthDate.day)) {
age--;
}
return '$age살';
}
// 사람 나이 환산 (강아지 기준 대략적 계산 - 소형견 기준 예시)
// 사람 나이 환산 (종별 계산법 적용)
String _calculateHumanAge(DateTime? birthDate, String species) {
if (birthDate == null) return '??살';
final now = DateTime.now();
int ageYears = now.year - birthDate.year;
// 생일이 안 지났으면 만 나이 적용
if (now.month < birthDate.month ||
(now.month == birthDate.month && now.day < birthDate.day)) {
ageYears--;
}
// 개월 수 계산 (햄스터/토끼 등 단명 동물용)
int ageMonths =
(now.year - birthDate.year) * 12 + now.month - birthDate.month;
if (now.day < birthDate.day) {
ageMonths--;
}
int humanAge = 0;
switch (species) {
case '강아지':
// 강아지: 1년=15살, 2년=24살, 3년+=5살씩
if (ageYears < 1)
humanAge = (ageMonths * 1.25).round(); // 15/12
else if (ageYears == 1)
humanAge = 15;
else if (ageYears == 2)
humanAge = 24;
else
humanAge = 24 + (ageYears - 2) * 5;
break;
case '고양이':
// 고양이: 1년=15살, 2년=24살, 3년+=4살씩
if (ageYears < 1)
humanAge = (ageMonths * 1.25).round();
else if (ageYears == 1)
humanAge = 15;
else if (ageYears == 2)
humanAge = 24;
else
humanAge = 24 + (ageYears - 2) * 4;
break;
case '햄스터':
// 햄스터: 1개월=약 5살, 1년=58살, 2년=70살, その後
// 단순화: 개월당 5살로 치되, 1년차부터 보정
// 1개월~: month * 5
humanAge = ageMonths * 5;
// 1년(12개월) = 60 근사치. 2년(24개월) = 120 (너무 많음).
// 햄스터는 2~3년이 수명이므로 보정 필요
// 1년=58살, 2년=70살, 3년=100살
if (ageMonths >= 12 && ageMonths < 24) {
// 1년~2년 사이: 58 + ((month-12) * 1) -> 1년 70까지 천천히
// 58 + (ageMonths - 12); // 12개월=58, 23개월=69
humanAge = 58 + (ageMonths - 12);
} else if (ageMonths >= 24) {
// 2년 이상: 70 + (month-24)*2.5 (3년차에 100되도록)
humanAge = 70 + ((ageMonths - 24) * 2.5).round();
}
break;
case '토끼':
// 토끼: 6개월=16, 1년=21, 2년=28, 이후 +6
if (ageMonths < 6)
humanAge = (ageMonths * 2.6).round(); // 16/6
else if (ageMonths < 12)
humanAge = 16 + (ageMonths - 6); // 16~21
else if (ageYears == 1)
humanAge = 21;
else if (ageYears == 2)
humanAge = 28;
else
humanAge = 28 + (ageYears - 2) * 6;
break;
default:
// 기타 (기니피그, 앵무새, 파충류 등): 강아지 로직 fallback 혹은 1:1
// 일단 강아지 로직을 따르되, 사용자가 인지하게끔
// 여기서는 그냥 강아지와 동일하게 처리 (사용자 요청: 미적용 동물 알려달라함)
if (ageYears < 1)
humanAge = (ageMonths * 1.25).round();
else if (ageYears == 1)
humanAge = 15;
else if (ageYears == 2)
humanAge = 24;
else
humanAge = 24 + (ageYears - 2) * 5;
break;
}
return '$humanAge살';
}
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.r),
image: const DecorationImage(
image: AssetImage('assets/img/profile_card_background.png'),
fit: BoxFit.cover,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 왼쪽: 프로필 이미지
// 왼쪽: 프로필 이미지
Container(
width: 120.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.r),
color: Colors.grey[200],
),
clipBehavior: Clip.hardEdge,
child: pet.profileImageUrl != null
? Image.network(
pet.profileImageUrl!,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Center(
child: SvgPicture.asset(
'assets/icons/profile_icon.svg',
width: 40.w,
colorFilter: ColorFilter.mode(
Colors.grey[400]!,
BlendMode.srcIn,
),
),
);
},
)
: Center(
child: SvgPicture.asset(
'assets/icons/profile_icon.svg',
width: 40.w,
colorFilter: ColorFilter.mode(
Colors.grey[400]!,
BlendMode.srcIn,
),
),
),
),
SizedBox(width: 10.w),
// 오른쪽: 정보 영역
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
Flexible(
child: Text(
pet.name,
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 22.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
),
overflow: TextOverflow.ellipsis,
),
),
if (pet.gender == '남아' || pet.gender == '여아') ...[
SizedBox(width: 6.w),
SvgPicture.asset(
pet.gender == '남아'
? 'assets/icons/male_icon.svg'
: 'assets/icons/female_icon.svg',
width: 20.w,
height: 20.w,
),
],
],
),
),
Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(20),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
PetFormScreen(petToEdit: pet),
),
).then((value) {
if (value == true && onPetUpdated != null) {
onPetUpdated!();
}
});
},
child: Padding(
padding: EdgeInsets.all(8.w),
child: Icon(
Icons.arrow_forward_ios,
size: 16.sp,
color: Colors.grey[400],
),
),
),
),
],
),
SizedBox(height: 2.h),
Text(
pet.breed,
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 14.sp,
color: Colors.grey[600],
),
),
SizedBox(height: 8.h),
// 정보 박스 (생일, 체중)
Row(
children: [
_buildInfoBox(
'생일',
pet.birthDate != null
? DateFormat('yy.MM.dd').format(pet.birthDate!)
: '??.??.??',
),
SizedBox(width: 8.w),
_buildInfoBox(
'체중',
pet.weight != null ? '${pet.weight}kg' : '--kg',
),
],
),
SizedBox(height: 8.h),
// 나이 정보
FittedBox(
fit: BoxFit.scaleDown,
alignment: Alignment.centerLeft,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'나이 ',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 14.sp,
color: Colors.grey[600],
height: 1.2,
),
),
Text(
_calculateAge(pet.birthDate),
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 15.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
height: 1.2,
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8.w),
child: Text(
'/',
style: TextStyle(
color: Colors.grey[300],
fontSize: 14.sp,
height: 1.2,
),
),
),
Text(
'사람나이 ',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 14.sp,
color: Colors.grey[600],
height: 1.2,
),
),
Text(
_calculateHumanAge(pet.birthDate, pet.species),
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 15.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
height: 1.2,
),
),
],
),
),
SizedBox(height: 6.h),
// 등록번호
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'등록번호 ',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 14.sp,
color: Colors.grey[600],
height: 1.2,
),
),
Expanded(
child: FittedBox(
fit: BoxFit.scaleDown,
alignment: Alignment.centerLeft,
child: Text(
pet.registrationNumber?.isNotEmpty == true
? pet.registrationNumber!
: '--',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 15.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
height: 1.2,
),
maxLines: 1,
),
),
),
],
),
],
),
),
],
),
),
);
}
Widget _buildInfoBox(String label, String value) {
return Expanded(
child: ClipRRect(
borderRadius: BorderRadius.circular(12.r),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.4),
border: Border.all(color: const Color(0xFFEEEEEE), width: 1),
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 12.sp,
color: Colors.grey[600],
),
),
SizedBox(height: 4.h),
Text(
value,
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 15.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
],
),
),
),
),
);
}
}