회원 가입 페이지(Register Screen), 설정 페이지(Settings_Screen) 약관 로직 개선 및 위치기반 서비스 동의 추가
This commit is contained in:
KIMGYEONGRAN
2025-12-08 11:01:56 +09:00
parent 260e09b3a5
commit 5ca7aec77e
2 changed files with 133 additions and 27 deletions

View File

@@ -15,6 +15,44 @@ const BoxShadow _cleanShadow = BoxShadow(
spreadRadius: 0,
);
const String _serviceTermContent = """
제1조 (목적)
본 약관은 메타큐랩 서비스 이용과 관련하여 회사와 회원의 권리, 의무 및 책임 사항, 기타 필요한 사항을 규정함을 목적으로 합니다.
제2조 (약관의 효력 및 변경)
1. 본 약관은 서비스를 이용하고자 하는 모든 회원에 대하여 그 효력을 발생합니다.
2. 회사는 관련 법령을 위배하지 않는 범위에서 본 약관을 개정할 수 있습니다.
3. 개정된 약관은 적용일자 및 개정 사유를 명시하여 현행 약관과 함께 서비스 화면에 게시합니다.
""";
const String _privacyTermContent = """
1. 수집하는 개인정보의 항목
회사는 회원가입, 상담, 서비스 신청 등을 위해 아래와 같은 개인정보를 수집하고 있습니다.
- 필수 항목: 아이디, 비밀번호, 이름, 전화번호, 이메일 주소
- 선택 항목: 닉네임, 마케팅 정보 수신 동의 여부
2. 개인정보의 수집 및 이용 목적
회사는 다음의 목적을 위해 개인정보를 수집 및 이용합니다.
- 서비스 제공에 관한 계약 이행 및 요금 정산
- 회원 관리 및 본인 확인
""";
const String _locationTermContent = """
1. 위치정보의 수집 및 이용 목적
회사는 이용자의 현재 위치를 확인하여 긴급 구조 요청, 주행 경로 기록, 주변 시설 검색 등 위치 기반 서비스를 제공하기 위해 위치정보를 수집 및 이용합니다.
2. 위치정보의 보유 및 이용 기간
회사는 위치정보의 수집 및 이용 목적이 달성된 후에는 해당 정보를 지체 없이 파기합니다. 단, 관련 법령의 규정에 의하여 보존할 필요가 있는 경우 법령에서 정한 기간 동안 보관합니다.
""";
const String _marketingTermContent = """
1. 수집 및 이용 목적
이벤트 정보 및 참여 기회 제공, 광고성 정보 제공 등 마케팅 활동을 위해 사용됩니다.
2. 수신 동의 철회
회원은 언제든지 설정 메뉴 또는 고객센터를 통해 마케팅 정보 수신 동의를 철회할 수 있습니다. 수신 동의를 철회하더라도 기본 서비스 이용에는 제한이 없습니다.
""";
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@@ -27,6 +65,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
bool _isRentalAlertEnabled = true;
bool _isStorageStatusAlert = true;
bool _isEnvSensorAlert = true;
bool _isMarketingAlertEnabled = true;
bool _isBiometricEnabled = false;
bool _isAutoLogoutEnabled = true;
@@ -331,15 +370,19 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
}
void _showTermsSheet(BuildContext context) {
void _showTermContentSheet(BuildContext context, String title, String content) {
_showCommonModal(
context,
'이용 약관',
title,
SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Text(
'제 1 조 (목적)\n이 약관은 스마트 헬멧 서비스(이하 "서비스")의 이용 조건 및 절차, 이용자와 회사의 권리, 의무, 책임 사항을 규정함을 목적으로 합니다.\n\n제 2 조 (용어의 정의)\n1. "이용자"란 앱에 접속하여 본 약관에 따라 서비스를 이용하는 회원을 말합니다.\n2. "헬멧"이란 회사가 대여하는 스마트 IoT 안전모를 말합니다.\n\n(이하 생략... 더미 데이터입니다.)\n\n제 3 조 (약관의 효력)\n본 약관은 서비스를 신청한 때부터 효력이 발생합니다.',
style: TextStyle(color: _subTextColor, height: 1.6),
child: SizedBox(
width: double.infinity,
child: Text(
content,
textAlign: TextAlign.start,
style: TextStyle(color: _subTextColor, height: 1.6),
),
),
),
);
@@ -723,6 +766,14 @@ class _SettingsScreenState extends State<SettingsScreen> {
(val) => setState(() => _isEnvSensorAlert = val),
showDivider: true,
),
_buildToggleItem(
'이벤트 및 마케팅 알림',
'혜택 및 소식 받기',
_isMarketingAlertEnabled,
(val) => setState(() => _isMarketingAlertEnabled = val),
showDivider: true,
onTapLabel: () => _showTermContentSheet(context, '마케팅 수신 동의', _marketingTermContent),
),
_buildDivider(16),
_buildInfoLink('알림 방식', Icons.notifications_active_outlined, value: '배너 + 진동', onTap: () => _showNotificationStyleSheet(context)),
],
@@ -769,7 +820,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
children: [
_buildInfoLink('버전 정보', null, value: _currentAppVersion, showArrow: false),
_buildDivider(16),
_buildInfoLink('이용 약관 및 개인정보 처리방침', Icons.article_outlined, onTap: () => _showTermsSheet(context)),
_buildInfoLink('서비스 이용약관', Icons.description_outlined, onTap: () => _showTermContentSheet(context, '서비스 이용약관', _serviceTermContent)),
_buildDivider(16),
_buildInfoLink('개인정보 처리방침', Icons.privacy_tip_outlined, onTap: () => _showTermContentSheet(context, '개인정보 처리방침', _privacyTermContent)),
_buildDivider(16),
_buildInfoLink('위치기반 서비스 이용약관', Icons.location_on_outlined, onTap: () => _showTermContentSheet(context, '위치기반 서비스 이용약관', _locationTermContent)),
_buildDivider(16),
_buildInfoLink('오픈소스 라이선스', Icons.code, onTap: () => _showLicenseSheet(context)),
_buildDivider(16),
@@ -838,7 +893,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
Widget _buildToggleItem(
String title, String subtitle, bool value, ValueChanged<bool> onChanged,
{required bool showDivider}) {
{required bool showDivider, VoidCallback? onTapLabel}) {
return Column(
children: [
Padding(
@@ -847,13 +902,25 @@ class _SettingsScreenState extends State<SettingsScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: TextStyle(color: _mainTextColor, fontSize: 14, fontWeight: FontWeight.w500)),
const SizedBox(height: 2),
Text(subtitle, style: TextStyle(color: _subTextColor, fontSize: 11)),
],
child: GestureDetector(
onTap: onTapLabel,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(title, style: TextStyle(color: _mainTextColor, fontSize: 14, fontWeight: FontWeight.w500)),
if (onTapLabel != null)
Padding(
padding: const EdgeInsets.only(left: 4.0),
child: Icon(Icons.info_outline, size: 14, color: _subTextColor),
),
],
),
const SizedBox(height: 2),
Text(subtitle, style: TextStyle(color: _subTextColor, fontSize: 11)),
],
),
),
),
Transform.scale(