520 lines
24 KiB
Dart
520 lines
24 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
const String _serviceTermContent =
|
|
'제1조 (목적)\n'
|
|
'본 약관은 (주)메타큐랩(이하 "회사")이 제공하는 공유 전동 킥보드용 스마트 안전모 보관함 및 관련 애플리케이션 서비스(이하 "서비스")의 이용과 관련하여 회사와 회원의 권리, 의무 및 책임사항, 기타 필요한 사항을 규정함을 목적으로 합니다.\n\n'
|
|
'제2조 (용어의 정의)\n'
|
|
'1. "서비스"란 회사가 제공하는 스마트 안전모 보관함 앱을 통해 안전모를 대여, 반납, 관리하는 모든 제반 서비스를 의미합니다.\n'
|
|
'2. "보관함"이란 안전모의 보관, 살균, 건조, 잠금 기능을 수행하는 물리적 하드웨어 장치를 말합니다.\n'
|
|
'3. "회원"이란 앱을 설치하고 본 약관에 동의하여 회사와 이용계약을 체결한 자를 말합니다.\n'
|
|
'4. "대여"란 앱을 통해 보관함의 잠금을 해제하고 안전모를 수령하는 행위를 말합니다.\n'
|
|
'5. "반납"이란 사용 후 안전모를 보관함에 넣고 문을 닫아 센서가 안전모를 인식하고 잠금이 완료된 상태를 말합니다.\n\n'
|
|
'제3조 (이용계약의 체결)\n'
|
|
'1. 이용계약은 회원이 되고자 하는 자(이하 "가입신청자")가 약관의 내용에 대하여 동의를 한 다음 회원가입 신청을 하고 회사가 이러한 신청을 승낙함으로써 체결됩니다.\n'
|
|
'2. 가입신청자는 앱 내에서 아이디(이메일), 비밀번호 등 필수 정보를 입력해야 하며, 회사는 필요시 본인 인증을 요구할 수 있습니다.\n\n'
|
|
'제4조 (서비스의 제공 및 기능)\n'
|
|
'회사는 회원에게 다음과 같은 서비스를 제공합니다.\n'
|
|
'1. 안전모 보관함 위치 찾기 (지도 및 리스트 제공)\n'
|
|
'2. 보관함 잠금장치 원격 제어 (대여/반납)\n'
|
|
'3. 안전모 살균 및 건조 상태 모니터링\n'
|
|
'4. 이용 내역 조회 및 알림 서비스\n\n'
|
|
'제5조 (대여 및 반납)\n'
|
|
'1. 회원은 앱을 통해 이용 가능한 보관함을 확인하고 잠금을 해제하여 안전모를 대여할 수 있습니다.\n'
|
|
'2. 회원은 이용 종료 후 안전모를 지정된 보관함에 넣고 문을 닫아야 합니다.\n'
|
|
'3. (반납의 완료) 반납 처리는 보관함 내부 센서가 안전모를 정상적으로 인식하고 문이 잠길 때 완료됩니다. 안전모가 감지되지 않거나 도어가 닫히지 않을 경우 반납으로 처리되지 않으며, 이에 따른 불이익은 회원이 부담합니다.\n'
|
|
'4. 센서 오류 등으로 반납 처리가 되지 않을 경우, 회원은 앱 내 "비상 신고 버튼" 또는 사진 업로드 기능을 통해 반납 사실을 증명해야 합니다.\n\n'
|
|
'제6조 (이용 요금 및 결제)\n'
|
|
'1. 서비스 이용 요금은 회사의 정책에 따르며 앱 내에 공지합니다.\n'
|
|
'2. 회원이 안전모를 분실하거나 파손한 경우, 회사는 별도의 실비 변상을 청구할 수 있습니다.\n\n'
|
|
'제7조 (살균 및 건조)\n'
|
|
'보관함은 반납 완료 후 자동으로 UV 살균 및 건조 기능을 수행합니다. 단, 회원은 착용 전 안전모의 상태를 육안으로 확인해야 하며, 오염 등이 심한 경우 이용을 중단하고 신고해야 합니다.\n\n'
|
|
'제8조 (회원의 의무)\n'
|
|
'1. 회원은 도로교통법 등 관련 법령에 따라 전동 킥보드 탑승 시 반드시 안전모를 착용해야 합니다.\n'
|
|
'2. 회원은 대여한 안전모를 제3자에게 양도하거나 대여해서는 안 됩니다.\n'
|
|
'3. 회원은 보관함 및 안전모를 파손하거나 기능을 임의로 조작해서는 안 됩니다.\n\n'
|
|
'제9조 (위치기반서비스의 내용)\n'
|
|
'회사는 회원의 위치 정보를 이용하여 주변 보관함 검색 기능을 제공하며, 회원의 위치 정보는 서비스 제공 목적 외에는 사용되지 않습니다.\n\n'
|
|
'제10조 (책임 제한)\n'
|
|
'1. 회사는 천재지변 또는 이에 준하는 불가항력으로 인하여 서비스를 제공할 수 없는 경우에는 서비스 제공에 관한 책임이 면제됩니다.\n'
|
|
'2. 회사는 회원의 귀책사유로 인한 서비스 이용의 장애에 대하여는 책임을 지지 않습니다.\n'
|
|
'3. 회원은 안전모 미착용 또는 올바르지 않은 착용으로 인해 발생한 사고에 대해 전적으로 책임을 지며, 회사는 이에 대해 책임을 지지 않습니다.\n\n'
|
|
'제11조 (서비스 알림)\n'
|
|
'회사는 회원의 안전한 이용을 위해 대여/반납 현황, 미반납 알림, 이상 감지 알림 등을 PUSH 알림으로 전송할 수 있습니다.\n\n'
|
|
'제12조 (준거법 및 재판관할)\n'
|
|
'본 약관에 명시되지 않은 사항은 대한민국의 관계 법령에 따르며, 서비스 이용으로 발생한 분쟁에 대해 소송이 제기되는 경우 회사의 본점 소재지를 관할하는 법원을 전속 관할법원으로 합니다.\n\n'
|
|
'부 칙\n'
|
|
'본 약관은 2025년 11월 28일부터 시행합니다.\n';
|
|
|
|
const String _privacyTermContent =
|
|
'(주)메타큐랩은 서비스 제공을 위하여 아래와 같이 귀하의 개인정보를 수집·이용합니다. 내용을 자세히 읽으신 후 동의해 주시기 바랍니다.\n\n'
|
|
'1. 수집 및 이용 목적\n'
|
|
'- 회원 가입 및 관리: 본인 확인, 개인 식별, 불량 회원의 부정이용 방지, 가입 의사 확인.\n'
|
|
'- 서비스 제공: 스마트 안전모 보관함 대여/반납 처리, 기기 제어, 이용 내역 관리, 살균/건조 상태 정보 제공.\n'
|
|
'- 고객 지원: 공지사항 전달, 서비스 장애 및 오류 신고 접수, 민원 처리.\n\n'
|
|
'2. 수집하는 개인정보 항목\n'
|
|
'- (필수) 아이디(이메일), 비밀번호, 이름, 휴대전화번호.\n'
|
|
'- (자동 수집) 기기 식별 정보(Device ID), PUSH 토큰, 서비스 이용 기록, 접속 로그.\n\n'
|
|
'3. 보유 및 이용 기간\n'
|
|
'회원 탈퇴 시까지 (단, 관계 법령에 따라 일정 기간 보존이 필요한 경우 해당 기간까지 보관)\n\n'
|
|
'4. 동의 거부 권리 및 불이익\n'
|
|
'귀하는 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다. 단, 필수 항목에 대한 동의를 거부할 경우 회원 가입 및 서비스 이용이 제한됩니다.\n';
|
|
|
|
const String _locationTermContent = """
|
|
1. 위치정보의 수집 및 이용 목적
|
|
회사는 이용자의 현재 위치를 확인하여 긴급 구조 요청, 주행 경로 기록, 주변 시설 검색 등 위치 기반 서비스를 제공하기 위해 위치정보를 수집 및 이용합니다.
|
|
|
|
2. 위치정보의 보유 및 이용 기간
|
|
회사는 위치정보의 수집 및 이용 목적이 달성된 후에는 해당 정보를 지체 없이 파기합니다. 단, 관련 법령의 규정에 의하여 보존할 필요가 있는 경우 법령에서 정한 기간 동안 보관합니다.
|
|
""";
|
|
|
|
const String _marketingTermContent =
|
|
'(주)메타큐랩이 제공하는 이벤트 및 혜택 등 마케팅 정보를 수신하는 것에 동의합니다.\n\n'
|
|
'1. 수집 및 이용 목적\n'
|
|
'- 신규 서비스(기능) 개발 및 맞춤 서비스 제공.\n'
|
|
'- 이벤트, 프로모션, 혜택 등 광고성 정보 제공.\n'
|
|
'- 서비스 이용 통계 및 설문조사.\n\n'
|
|
'2. 수집하는 개인정보 항목\n'
|
|
'- 이름, 휴대전화번호, 이메일, PUSH 토큰.\n\n'
|
|
'3. 보유 및 이용 기간\n'
|
|
'- 회원 탈퇴 또는 동의 철회 시까지\n\n'
|
|
'4. 전송 방법\n'
|
|
'- 앱 푸시(App Push) 알림, SMS(문자메시지), 이메일 등.\n\n'
|
|
'5. 동의 거부 권리\n'
|
|
'귀하는 마케팅 정보 수신에 대한 동의를 거부할 수 있습니다. 동의를 거부하더라도 회원 가입 및 기본 서비스 이용에는 제한이 없습니다. 다만, 이벤트 및 혜택 정보 제공이 제한될 수 있습니다.\n';
|
|
|
|
class RegisterScreen extends StatefulWidget {
|
|
const RegisterScreen({super.key});
|
|
|
|
@override
|
|
State<RegisterScreen> createState() => _RegisterScreenState();
|
|
}
|
|
|
|
class _RegisterScreenState extends State<RegisterScreen> {
|
|
final TextEditingController _idController = TextEditingController();
|
|
final TextEditingController _pwController = TextEditingController();
|
|
final TextEditingController _nameController = TextEditingController();
|
|
final TextEditingController _nicknameController = TextEditingController();
|
|
final TextEditingController _phoneController = TextEditingController();
|
|
final TextEditingController _emailController = TextEditingController();
|
|
|
|
bool _isServiceAgreed = false;
|
|
bool _isPrivacyAgreed = false;
|
|
bool _isLocationAgreed = false;
|
|
bool _isMarketingAgreed = false;
|
|
|
|
final Color mainBlueColor = const Color(0xFF0033CC);
|
|
final Color backgroundColor = const Color(0xFFF5F6F8);
|
|
final Color iconColor = const Color(0xFF8899A6);
|
|
|
|
@override
|
|
void dispose() {
|
|
_idController.dispose();
|
|
_pwController.dispose();
|
|
_nameController.dispose();
|
|
_nicknameController.dispose();
|
|
_phoneController.dispose();
|
|
_emailController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _tryRegister() {
|
|
if (_idController.text.isEmpty) return _showError('아이디를 입력해주세요.');
|
|
if (_pwController.text.isEmpty) return _showError('비밀번호를 입력해주세요.');
|
|
if (_emailController.text.isEmpty) return _showError('이메일을 입력해주세요.');
|
|
if (_nameController.text.isEmpty) return _showError('이름을 입력해주세요.');
|
|
if (_phoneController.text.isEmpty) return _showError('전화번호를 입력해주세요.');
|
|
if (_phoneController.text.length < 12) return _showError('올바른 전화번호를 입력해주세요.');
|
|
if (_nicknameController.text.isEmpty) return _showError('닉네임을 입력해주세요.');
|
|
|
|
if (!_isServiceAgreed || !_isPrivacyAgreed || !_isLocationAgreed) {
|
|
return _showError('(필수) 약관에 모두 동의해주세요.');
|
|
}
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: const Text('회원가입이 완료되었습니다! 환영합니다.'),
|
|
backgroundColor: mainBlueColor,
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
|
|
Future.delayed(const Duration(seconds: 1), () {
|
|
if (mounted) Navigator.pop(context);
|
|
});
|
|
}
|
|
|
|
void _showError(String message) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(message),
|
|
backgroundColor: Colors.redAccent,
|
|
behavior: SnackBarBehavior.floating,
|
|
duration: const Duration(seconds: 2),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showTermDetails(String title, String content) {
|
|
String fullContent = content;
|
|
|
|
showDialog(
|
|
context: context,
|
|
builder: (context) => Dialog(
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
|
backgroundColor: Colors.white,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.only(left: 20, right: 10, top: 15, bottom: 10),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
title,
|
|
style: const TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.black87,
|
|
),
|
|
maxLines: 2,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
IconButton(
|
|
icon: const Icon(Icons.close, color: Colors.grey),
|
|
onPressed: () => Navigator.pop(context),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 1, thickness: 1),
|
|
Flexible(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(20),
|
|
child: Text(
|
|
fullContent,
|
|
style: const TextStyle(fontSize: 14, height: 1.6, color: Colors.black54),
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(20),
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
child: ElevatedButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: mainBlueColor,
|
|
foregroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
elevation: 0,
|
|
),
|
|
child: const Text(
|
|
'확인',
|
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: backgroundColor,
|
|
appBar: AppBar(
|
|
backgroundColor: backgroundColor,
|
|
elevation: 0,
|
|
scrolledUnderElevation: 0,
|
|
leading: IconButton(
|
|
icon: const Icon(Icons.arrow_back_ios, color: Colors.black),
|
|
onPressed: () => Navigator.pop(context),
|
|
),
|
|
title: const Text(
|
|
'회원가입',
|
|
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 18),
|
|
),
|
|
centerTitle: true,
|
|
),
|
|
body: SafeArea(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 30.0),
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: Colors.grey.shade200),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.03),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
children: [
|
|
_buildInputRow(
|
|
icon: Icons.account_circle,
|
|
hint: '아이디',
|
|
controller: _idController,
|
|
),
|
|
_buildDivider(),
|
|
_buildInputRow(
|
|
icon: Icons.lock_outline,
|
|
hint: '비밀번호',
|
|
controller: _pwController,
|
|
isObscure: true,
|
|
),
|
|
_buildDivider(),
|
|
_buildInputRow(
|
|
icon: Icons.email_outlined,
|
|
hint: '이메일',
|
|
controller: _emailController,
|
|
keyboardType: TextInputType.emailAddress,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: Colors.grey.shade200),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.03),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
children: [
|
|
_buildInputRow(
|
|
icon: Icons.account_circle,
|
|
hint: '이름',
|
|
controller: _nameController,
|
|
),
|
|
_buildDivider(),
|
|
_buildInputRow(
|
|
icon: Icons.phone_iphone_outlined,
|
|
hint: '전화번호',
|
|
controller: _phoneController,
|
|
keyboardType: TextInputType.phone,
|
|
isPhone: true,
|
|
),
|
|
_buildDivider(),
|
|
_buildInputRow(
|
|
icon: Icons.person_outline,
|
|
hint: '닉네임',
|
|
controller: _nicknameController,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 24),
|
|
|
|
Container(
|
|
padding: const EdgeInsets.all(20.0),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: Colors.grey.shade200),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.03),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'약관 동의',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
),
|
|
const SizedBox(height: 16),
|
|
_buildAgreementRow(
|
|
title: '(필수) 서비스 이용약관 동의',
|
|
value: _isServiceAgreed,
|
|
onChanged: (v) => setState(() => _isServiceAgreed = v!),
|
|
details: _serviceTermContent,
|
|
),
|
|
const SizedBox(height: 12),
|
|
_buildAgreementRow(
|
|
title: '(필수) 개인정보 수집 및 이용 동의',
|
|
value: _isPrivacyAgreed,
|
|
onChanged: (v) => setState(() => _isPrivacyAgreed = v!),
|
|
details: _privacyTermContent,
|
|
),
|
|
const SizedBox(height: 12),
|
|
_buildAgreementRow(
|
|
title: '(필수) 위치기반 서비스 이용약관 동의',
|
|
value: _isLocationAgreed,
|
|
onChanged: (v) => setState(() => _isLocationAgreed = v!),
|
|
details: _locationTermContent,
|
|
),
|
|
const SizedBox(height: 12),
|
|
_buildAgreementRow(
|
|
title: '(선택) 이벤트 및 마케팅 수신 동의',
|
|
value: _isMarketingAgreed,
|
|
onChanged: (v) => setState(() => _isMarketingAgreed = v!),
|
|
details: _marketingTermContent,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 32),
|
|
|
|
ElevatedButton(
|
|
onPressed: _tryRegister,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: mainBlueColor,
|
|
foregroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(vertical: 18),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
elevation: 0,
|
|
minimumSize: const Size(double.infinity, 56),
|
|
),
|
|
child: const Text(
|
|
'가입하기',
|
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
),
|
|
),
|
|
const SizedBox(height: 30),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDivider() {
|
|
return Divider(height: 1, thickness: 1, color: Colors.grey.shade100, indent: 50, endIndent: 20);
|
|
}
|
|
|
|
Widget _buildInputRow({
|
|
required IconData icon,
|
|
required String hint,
|
|
required TextEditingController controller,
|
|
bool isObscure = false,
|
|
TextInputType keyboardType = TextInputType.text,
|
|
bool isPhone = false,
|
|
}) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
|
child: Row(
|
|
children: [
|
|
Icon(icon, color: iconColor, size: 24),
|
|
const SizedBox(width: 16),
|
|
Expanded(
|
|
child: TextField(
|
|
controller: controller,
|
|
obscureText: isObscure,
|
|
keyboardType: keyboardType,
|
|
inputFormatters: isPhone
|
|
? [
|
|
FilteringTextInputFormatter.digitsOnly,
|
|
_PhoneNumberFormatter(),
|
|
LengthLimitingTextInputFormatter(13),
|
|
]
|
|
: [],
|
|
decoration: InputDecoration(
|
|
hintText: hint,
|
|
hintStyle: TextStyle(color: Colors.grey.shade400, fontSize: 15),
|
|
border: InputBorder.none,
|
|
focusedBorder: InputBorder.none,
|
|
enabledBorder: InputBorder.none,
|
|
contentPadding: const EdgeInsets.symmetric(vertical: 14),
|
|
),
|
|
style: const TextStyle(fontSize: 16, color: Colors.black87),
|
|
cursorColor: mainBlueColor,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildAgreementRow({
|
|
required String title,
|
|
required bool value,
|
|
required ValueChanged<bool?> onChanged,
|
|
required String details,
|
|
}) {
|
|
return Row(
|
|
children: [
|
|
SizedBox(
|
|
width: 24,
|
|
height: 24,
|
|
child: Checkbox(
|
|
value: value,
|
|
activeColor: mainBlueColor,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
|
|
side: BorderSide(color: Colors.grey.shade300, width: 1.5),
|
|
onChanged: onChanged,
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: GestureDetector(
|
|
onTap: () => onChanged(!value),
|
|
child: Text(
|
|
title,
|
|
style: const TextStyle(fontSize: 14, color: Colors.black87),
|
|
),
|
|
),
|
|
),
|
|
IconButton(
|
|
onPressed: () => _showTermDetails(title, details),
|
|
icon: const Icon(Icons.arrow_forward_ios_rounded, color: Colors.grey, size: 14),
|
|
padding: EdgeInsets.zero,
|
|
constraints: const BoxConstraints(),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _PhoneNumberFormatter extends TextInputFormatter {
|
|
@override
|
|
TextEditingValue formatEditUpdate(
|
|
TextEditingValue oldValue, TextEditingValue newValue) {
|
|
var text = newValue.text;
|
|
if (newValue.selection.baseOffset == 0) return newValue;
|
|
var buffer = StringBuffer();
|
|
for (int i = 0; i < text.length; i++) {
|
|
buffer.write(text[i]);
|
|
var nonZeroIndex = i + 1;
|
|
if (nonZeroIndex <= 3) {
|
|
if (nonZeroIndex % 3 == 0 && nonZeroIndex != text.length) buffer.write('-');
|
|
} else {
|
|
if (nonZeroIndex % 7 == 0 && nonZeroIndex != text.length && nonZeroIndex > 4) buffer.write('-');
|
|
}
|
|
}
|
|
var string = buffer.toString();
|
|
return newValue.copyWith(text: string, selection: TextSelection.collapsed(offset: string.length));
|
|
}
|
|
} |