rup-project/app/lib/screens/terms_agreement_screen.dart

387 lines
14 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import 'identity_verification_screen.dart';
import '../services/auth_service.dart'; // Import AuthService
import '../data/terms_data.dart';
import '../widgets/common/custom_app_bar.dart';
class TermsAgreementScreen extends StatefulWidget {
final bool isViewOnly;
final String? idToken;
const TermsAgreementScreen({
super.key,
this.isViewOnly = false,
this.idToken,
});
@override
State<TermsAgreementScreen> createState() => _TermsAgreementScreenState();
}
class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
final List<bool> _checks = [false, false, false, false, false, false];
bool get _isAllChecked => _checks.every((completed) => completed);
bool get _isRequiredChecked =>
_checks[0] && _checks[1] && _checks[2] && _checks[3];
void _toggleAll() {
setState(() {
bool newValue = !_isAllChecked;
for (int i = 0; i < _checks.length; i++) {
_checks[i] = newValue;
}
});
}
void _toggleItem(int index) {
setState(() {
_checks[index] = !_checks[index];
});
}
String _getTermContent(int index) {
if (index >= 0 && index < TermsData.terms.length) {
return TermsData.terms[index]['content'] ?? '내용이 없습니다.';
}
return '내용이 없습니다.';
}
void _showTermDetail(BuildContext context, String title, int index) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) {
return DraggableScrollableSheet(
initialChildSize: 0.7,
minChildSize: 0.5,
maxChildSize: 0.9,
builder: (_, controller) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20.r)),
),
padding: EdgeInsets.all(20.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
width: 40.w,
height: 4.h,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(2.r),
),
),
),
SizedBox(height: 20.h),
Text(
title,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
),
),
SizedBox(height: 20.h),
Expanded(
child: SingleChildScrollView(
controller: controller,
child: Text(
_getTermContent(index),
style: TextStyle(
fontSize: 15.sp,
height: 1.6,
fontFamily: 'SCDream',
color: Colors.black87,
),
),
),
),
SizedBox(height: 20.h),
SizedBox(
width: double.infinity,
height: 52.h,
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFF7500),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.r),
),
elevation: 0,
),
child: Text(
'확인',
style: TextStyle(
color: Colors.white,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
),
),
),
),
],
),
);
},
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: CustomAppBar(title: widget.isViewOnly ? '이용 약관' : '회원가입'),
body: SafeArea(
child: Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20.h),
// Header Area
Row(
children: [
Image.asset(
'assets/img/foot.png',
width: 24.w,
height: 24.h,
),
SizedBox(width: 8.w),
Text(
'서비스 이용 약관',
style: TextStyle(
fontSize: 22.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
color: Colors.black,
),
),
],
),
SizedBox(height: 8.h),
Text(
widget.isViewOnly
? 'RUP 서비스의 이용 약관 내용입니다.'
: '서비스 이용을 위해 약관에 동의해주세요.',
style: TextStyle(
fontSize: 15.sp,
color: Colors.black54,
fontFamily: 'SCDream',
),
),
SizedBox(height: 30.h),
// All Agree Box - *ViewOnly 모드에서는 숨김*
if (!widget.isViewOnly) ...[
InkWell(
onTap: () => _toggleAll(),
borderRadius: BorderRadius.circular(8.r),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 16.h,
horizontal: 16.w,
),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(8.r),
),
child: Row(
children: [
Icon(
_isAllChecked
? Icons.radio_button_checked
: Icons.radio_button_off,
color: _isAllChecked
? const Color(0xFFFF7500)
: Colors.grey,
),
SizedBox(width: 12.w),
Text(
'모든 약관에 동의합니다.',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
),
),
],
),
),
),
SizedBox(height: 20.h),
Divider(height: 1.h, color: const Color(0xFFEEEEEE)),
SizedBox(height: 10.h),
],
// Individual Items
_buildTermItem(0, '이용약관 동의', isRequired: true),
_buildTermItem(1, '개인정보 수집 및 이용 동의', isRequired: true),
_buildTermItem(2, '제 3자 제공 동의', isRequired: true),
_buildTermItem(3, '만 14세 이상 사용자', isRequired: true),
_buildTermItem(4, '위치정보 이용 동의', isRequired: false),
_buildTermItem(5, '마케팅 수신 동의', isRequired: false),
],
),
),
),
// Bottom Button
Padding(
padding: EdgeInsets.fromLTRB(20.w, 10.h, 20.w, 20.h),
child: SizedBox(
width: double.infinity,
height: 52.h,
child: ElevatedButton(
onPressed: widget.isViewOnly
? () => Navigator.pop(context)
: (_isRequiredChecked
? () async {
if (widget.idToken != null) {
// 실제 가입 요청 (DB 생성)
final success = await AuthService()
.registerWithGoogle(widget.idToken!);
if (success && context.mounted) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const IdentityVerificationScreen(),
),
);
} else if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('회원가입 처리에 실패했습니다.'),
),
);
}
} else {
// idToken이 없는 경우 (테스트 등) - 그냥 진행
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const IdentityVerificationScreen(),
),
);
}
}
: null),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFF7500),
disabledBackgroundColor: Colors.grey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.r),
),
elevation: 0,
),
child: Text(
widget.isViewOnly ? '닫기' : '동의하고 본인 인증하기',
style: TextStyle(
color: Colors.white,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
),
),
),
),
),
],
),
),
);
}
Widget _buildTermItem(int index, String title, {required bool isRequired}) {
// ViewOnly 모드에서는 체크박스 숨김
// ViewOnly 모드에서는 텍스트 클릭 시 모달 띄우기 (토글 X)
return Padding(
padding: EdgeInsets.symmetric(vertical: 4.h),
child: Row(
children: [
Expanded(
child: InkWell(
onTap: () {
if (!widget.isViewOnly) {
_toggleItem(index);
} else {
// ViewOnly일 땐 텍스트 눌러도 모달 띄우기 (편의성)
_showTermDetail(context, title, index);
}
},
borderRadius: BorderRadius.circular(8.r),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 8.w),
child: Row(
children: [
// 체크 Icon - *ViewOnly 모드에서는 숨김*
if (!widget.isViewOnly) ...[
Icon(
Icons.check,
size: 20.w,
color: _checks[index]
? const Color(0xFFFF7500)
: Colors.grey[300],
),
SizedBox(width: 12.w),
],
Text(
isRequired ? '필수' : '선택',
style: TextStyle(
color: isRequired
? const Color(0xFFFF7500)
: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 14.sp,
fontFamily: 'SCDream',
),
),
SizedBox(width: 8.w),
Expanded(
child: Text(
title,
style: TextStyle(
fontSize: 15.sp,
color: Colors.black87,
fontFamily: 'SCDream',
),
),
),
],
),
),
),
),
IconButton(
onPressed: () => _showTermDetail(context, title, index),
icon: Icon(
Icons.arrow_forward_ios,
size: 14.w,
color: Colors.black,
),
splashRadius: 20.r,
padding: EdgeInsets.all(12.w),
constraints: const BoxConstraints(),
),
],
),
);
}
}