diff --git a/android/app/src/main/res/drawable-hdpi/splash.png b/android/app/src/main/res/drawable-hdpi/splash.png new file mode 100644 index 0000000..0f058c0 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-mdpi/splash.png b/android/app/src/main/res/drawable-mdpi/splash.png new file mode 100644 index 0000000..9668894 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png new file mode 100644 index 0000000..8e21404 Binary files /dev/null and b/android/app/src/main/res/drawable-v21/background.png differ diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml index f74085f..3cc4948 100644 --- a/android/app/src/main/res/drawable-v21/launch_background.xml +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -1,12 +1,9 @@ - - - - - + + + + + + diff --git a/android/app/src/main/res/drawable-xhdpi/splash.png b/android/app/src/main/res/drawable-xhdpi/splash.png new file mode 100644 index 0000000..341554c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/splash.png b/android/app/src/main/res/drawable-xxhdpi/splash.png new file mode 100644 index 0000000..e39e843 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/splash.png b/android/app/src/main/res/drawable-xxxhdpi/splash.png new file mode 100644 index 0000000..0464e12 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..8e21404 Binary files /dev/null and b/android/app/src/main/res/drawable/background.png differ diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml index 304732f..3cc4948 100644 --- a/android/app/src/main/res/drawable/launch_background.xml +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -1,12 +1,9 @@ - - - - - + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4..8cde96e 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b7..d869d94 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 09d4391..6da61c4 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d..0cdbe2a 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372e..0114338 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values-night-v31/styles.xml b/android/app/src/main/res/values-night-v31/styles.xml new file mode 100644 index 0000000..5fef228 --- /dev/null +++ b/android/app/src/main/res/values-night-v31/styles.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml index 06952be..dbc9ea9 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/android/app/src/main/res/values-night/styles.xml @@ -5,6 +5,10 @@ @drawable/launch_background + false + false + false + shortEdges + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index cb1ef88..0d1fa8f 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -5,6 +5,10 @@ @drawable/launch_background + false + false + false + shortEdges - NSPhotoLibraryUsageDescription - 이 앱이 사진 라이브러리에 접근할 수 있도록 허용합니다. - + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + 올스코어 + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + allscore_app + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + GADApplicationIdentifier + ca-app-pub-3151339278746301~1689299887 + + NSPhotoLibraryUsageDescription + 이 앱이 사진 라이브러리에 접근할 수 있도록 허용합니다. + UIStatusBarHidden + + diff --git a/lib/config/config.dart b/lib/config/config.dart index abea696..f7aef9d 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -1,4 +1,8 @@ class Config { + // 테스트 광고 단위 ID static const String testAdUnitId = 'ca-app-pub-3940256099942544/6300978111'; + // 실제 광고 단위 ID static const String realAdUnitId = 'ca-app-pub-3940256099942544/6300978111'; + // 서버 주소 + static const String baseUrl = 'https://eldsoft.com:8097'; } \ No newline at end of file diff --git a/lib/dialogs/survey_dialog.dart b/lib/dialogs/survey_dialog.dart index c45e744..ee0bf1e 100644 --- a/lib/dialogs/survey_dialog.dart +++ b/lib/dialogs/survey_dialog.dart @@ -1,37 +1,20 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; - -// 예시: 설문 참여 버튼을 눌렀을 때 이동할 임시 설문 페이지 -// 실제 구현에서는 SurveyPage를 만들어 사용하시면 됩니다. -class SurveyPage extends StatelessWidget { - const SurveyPage({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('임시 설문 페이지'), - backgroundColor: Colors.black, - ), - body: const Center( - child: Text('여기는 설문 페이지입니다 (임시).'), - ), - ); - } -} +import '../survey/survey_page.dart'; /// 팝업(모달) 자체를 보여주는 함수 -Future showSurveyDialog(BuildContext context) async { +Future showSurveyDialog(BuildContext context, String nickname) async { showDialog( context: context, barrierDismissible: false, // 바깥 영역 터치로 닫기 방지 - builder: (_) => const SurveyDialog(), + builder: (_) => SurveyDialog(nickname: nickname), ); } /// 실제 AlertDialog 형태의 위젯 class SurveyDialog extends StatefulWidget { - const SurveyDialog({Key? key}) : super(key: key); + final String nickname; + const SurveyDialog({Key? key, required this.nickname}) : super(key: key); @override State createState() => _SurveyDialogState(); @@ -99,7 +82,7 @@ class _SurveyDialogState extends State { // 임시 설문 페이지로 이동 Navigator.push( context, - MaterialPageRoute(builder: (_) => const SurveyPage()), + MaterialPageRoute(builder: (_) => SurveyPage(nickname: widget.nickname)), ); }, style: TextButton.styleFrom(backgroundColor: Colors.black), diff --git a/lib/plugins/api.dart b/lib/plugins/api.dart index 0a31c48..447ca83 100644 --- a/lib/plugins/api.dart +++ b/lib/plugins/api.dart @@ -2,9 +2,10 @@ import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; import 'package:image_picker/image_picker.dart'; +import '../config/config.dart'; class Api { - static const String baseUrl = 'https://eldsoft.com:8097'; + static const String baseUrl = Config.baseUrl; // 사용자 정보를 업데이트하는 메서드 static Future> serverRequest({ @@ -32,8 +33,6 @@ class Api { if (response.statusCode == 200) { String responseBody = utf8.decode(response.bodyBytes); final Map jsonResponse = jsonDecode(responseBody); - print('응답: $jsonResponse'); - print('응답[result]: ${jsonResponse['result']}'); await prefs.setString('auth_token', jsonResponse['auth']['token']); res = { diff --git a/lib/survey/survey_page.dart b/lib/survey/survey_page.dart new file mode 100644 index 0000000..ae7d0bb --- /dev/null +++ b/lib/survey/survey_page.dart @@ -0,0 +1,442 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; // ★ 숫자만 입력 위해 +import 'package:http/http.dart' as http; +import 'dart:convert'; + +// 서버 API +import '../plugins/api.dart'; + +// 메인 페이지 +import '../views/room/main_page.dart'; + +// 알람 모달창 +import '../dialogs/response_dialog.dart'; + +class SurveyPage extends StatefulWidget { + final String nickname; + + const SurveyPage({ + Key? key, + required this.nickname, + }) : super(key: key); + + @override + State createState() => _SurveyPageState(); +} + +class _SurveyPageState extends State { + // 현재 페이지 인덱스 (0~4) + int _currentIndex = 0; + + // 전체 질문 목록 (5개 예시) + List _questions = []; + List _questionsOriginal = []; + + /// 사용자가 입력한 답변(5개) + final List _answers = List.filled(5, null, growable: false); + + // 각 페이지별 라디오 선택 값 + final Map _selectedRadioValue = {}; + + // 각 페이지별 텍스트필드 컨트롤러 + final Map _textControllers = {}; + + @override + void initState() { + super.initState(); + + // 질문들 세팅 + _questions = [ + "Q1. ${widget.nickname}님의 나이는 어떻게 되나요?", + "Q2. ${widget.nickname}님의 직업이 무엇인가요?", + "Q3. ${widget.nickname}님은 올스코어 앱을 어떻게 알게 됐나요?", + "Q4. ${widget.nickname}님은 올스코어 앱을 어디서 경험하셨나요?", + "Q5. 올스코어를 계속 사용할 의사가 있나요?", + ]; + + _questionsOriginal = [ + "나이는 어떻게 되나요?", + "직업이 무엇인가요?", + "올스코어 앱을 어떻게 알게 됐나요?", + "올스코어 앱을 어디서 경험하셨나요?", + "올스코어를 계속 사용할 의사가 있나요?", + ]; + + // 페이지마다 TextEditingController 초기화 + for (int i = 0; i < _questions.length; i++) { + _textControllers[i] = TextEditingController(); + } + } + + @override + void dispose() { + // TextController 정리 + for (var ctrl in _textControllers.values) { + ctrl.dispose(); + } + super.dispose(); + } + + /// (좌측 상단) 설문 그만하기 + Future _onExitSurvey() async { + // 필요 시 "정말 나가시겠습니까?" 등 확인 모달 추가 가능 + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (_) => const MainPage()), + (route) => false, + ); + } + + /// 다음 버튼 + void _onNext() { + if (!_validateCurrentPage()) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('값을 모두 입력해 주세요.')), + ); + return; + } + + if (_currentIndex < _questions.length - 1) { + setState(() { + _currentIndex++; + }); + } + } + + /// 이전 버튼 + void _onPrev() { + if (_currentIndex > 0) { + setState(() { + _currentIndex--; + }); + } + } + + /// 제출하기 + Future _onSubmit() async { + // 마지막 페이지도 값 확인 + if (!_validateCurrentPage()) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('값을 모두 입력해 주세요.')), + ); + return; + } + + // body: {"QNA": ["질문1","답변1","질문2","답변2", ... ]} + final List qnaList = []; + for (int i = 0; i < _questionsOriginal.length; i++) { + qnaList.add(_questionsOriginal[i]); + qnaList.add(_answers[i] ?? ''); + } + + final requestBody = { + "QNA": qnaList.toString(), + }; + print('requestBody: $requestBody'); + + try { + final response = await Api.serverRequest(uri: '/survey/collect', body: requestBody); + if (response['result'] == 'OK') { + final resp = response['response'] ?? {}; + if (resp['result'] == 'OK') { + // 설문 제출 성공 + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('설문이 제출되었습니다. 감사합니다!')), + ); + Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false); + } else { + showResponseDialog(context, '오류', '설문 제출 실패'); + } + } else { + showResponseDialog(context, '오류', '설문 제출 실패'); + } + } catch (e) { + showResponseDialog(context, '오류', '설문 제출 실패'); + } + } + + /// 현재 페이지 입력값이 유효한지 체크 + _answers에 저장 + bool _validateCurrentPage() { + final index = _currentIndex; + String? answer; + + switch (index) { + case 0: + // 나이(숫자만) + final txt = _textControllers[index]?.text.trim() ?? ''; + if (txt.isEmpty) { + return false; + } + answer = '$txt 세'; + break; + + case 1: + // 직업 + final selected = _selectedRadioValue[index]; + if (selected == null || selected.isEmpty) { + return false; + } + answer = selected; + break; + + case 2: + // 앱 알게된 경로 + final selected2 = _selectedRadioValue[index]; + if (selected2 == null || selected2.isEmpty) { + return false; + } + if (selected2 == '기타') { + final etc = _textControllers[index]?.text.trim() ?? ''; + if (etc.isEmpty) { + return false; + } + answer = "기타($etc)"; + } else { + answer = selected2; + } + break; + + case 3: + // 어디서 경험? + final sel3 = _selectedRadioValue[index]; + if (sel3 == null || sel3.isEmpty) { + return false; + } + answer = sel3; + break; + + case 4: + // 계속 사용할 의사? + final sel4 = _selectedRadioValue[index]; + if (sel4 == null || sel4.isEmpty) { + return false; + } + final comment = _textControllers[index]?.text.trim() ?? ''; + answer = sel4 + (comment.isNotEmpty ? " / 의견: $comment" : ""); + break; + + default: + return false; + } + + _answers[index] = answer; + return true; + } + + @override + Widget build(BuildContext context) { + final questionText = _questions[_currentIndex]; + final pageNumber = _currentIndex + 1; + final totalPage = _questions.length; + + return WillPopScope( + onWillPop: () async { + _onExitSurvey(); + return false; + }, + child: Scaffold( + appBar: AppBar( + // 좌측 위 '설문 그만하기' 버튼 + leadingWidth: 120, // 버튼 가로폭 살짝 넓힘 + leading: TextButton( + onPressed: _onExitSurvey, + child: const Text( + '설문 그만하기', + style: TextStyle(color: Colors.white), + ), + ), + title: Text('설문조사 ($pageNumber/$totalPage)'), + backgroundColor: Colors.black, + ), + body: SingleChildScrollView( + child: Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(16), + child: Column( + // 중앙 정렬 + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // 질문 + Text( + questionText, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), + // 페이지별 UI + _buildSurveyPage(_currentIndex), + ], + ), + ), + ), + bottomNavigationBar: Container( + color: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + if (_currentIndex > 0) + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom(backgroundColor: Colors.grey), + onPressed: _onPrev, + child: const Text('이전'), + ), + ), + if (_currentIndex > 0) const SizedBox(width: 8), + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom(backgroundColor: Colors.black), + onPressed: (_currentIndex < totalPage - 1) ? _onNext : _onSubmit, + child: Text( + (_currentIndex < totalPage - 1) ? '다음' : '제출하기', + style: const TextStyle(color: Colors.white), + ), + ), + ), + ], + ), + ), + ), + ); + } + + /// 페이지별 UI + Widget _buildSurveyPage(int index) { + switch (index) { + case 0: + // 나이 (숫자 입력) + return Column( + children: [ + const Text('(예: 나이를 숫자로 입력해 주세요.)', + textAlign: TextAlign.center), + const SizedBox(height: 16), + TextField( + controller: _textControllers[index], + keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], // 숫자만 입력 + textAlign: TextAlign.center, // 중앙정렬 + decoration: const InputDecoration( + labelText: '나이', + border: OutlineInputBorder(), + ), + ), + ], + ); + + case 1: + // 직업 + final jobs = ['학생', '회사원', '전문직', '교수/교사', '기술직', '공무원', '예술/스포츠', '기타']; + return Column( + mainAxisSize: MainAxisSize.min, + children: jobs.map((job) { + return RadioListTile( + title: Text(job, textAlign: TextAlign.center), + value: job, + groupValue: _selectedRadioValue[index], + onChanged: (val) { + setState(() { + _selectedRadioValue[index] = val!; + }); + }, + ); + }).toList(), + ); + + case 2: + // 알게된 경로 + final paths = ['친구/지인 추천', '소셜 미디어', '블로그/온라인 리뷰', '학교나 직장', '기타']; + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + ...paths.map((p) { + return RadioListTile( + title: Text(p, textAlign: TextAlign.center), + value: p, + groupValue: _selectedRadioValue[index], + onChanged: (val) { + setState(() { + _selectedRadioValue[index] = val!; + }); + }, + ); + }).toList(), + if (_selectedRadioValue[index] == '기타') + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: TextField( + controller: _textControllers[index], + textAlign: TextAlign.center, + decoration: const InputDecoration( + labelText: '기타 내용을 입력해 주세요.', + border: OutlineInputBorder(), + ), + ), + ), + ], + ); + + case 3: + // 어디서 경험? + final places = ['가족과 함께', '친구들과 모임', '학교 교육 목적', '직장 동호회', '카페나 공공장소', '여행 중', '기타']; + return Column( + mainAxisSize: MainAxisSize.min, + children: places.map((pl) { + return RadioListTile( + title: Text(pl, textAlign: TextAlign.center), + value: pl, + groupValue: _selectedRadioValue[index], + onChanged: (val) { + setState(() { + _selectedRadioValue[index] = val!; + }); + }, + ); + }).toList(), + ); + + case 4: + // 계속 사용할 의사? + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + RadioListTile( + title: const Text('네', textAlign: TextAlign.center), + value: '네', + groupValue: _selectedRadioValue[index], + onChanged: (val) { + setState(() { + _selectedRadioValue[index] = val!; + }); + }, + ), + RadioListTile( + title: const Text('아니오', textAlign: TextAlign.center), + value: '아니오', + groupValue: _selectedRadioValue[index], + onChanged: (val) { + setState(() { + _selectedRadioValue[index] = val!; + }); + }, + ), + const SizedBox(height: 16), + const Text('추가 의견이 있다면 자유롭게 작성해 주세요.', textAlign: TextAlign.center), + const SizedBox(height: 8), + TextField( + controller: _textControllers[index], + maxLines: 3, + textAlign: TextAlign.center, + decoration: const InputDecoration( + hintText: 'ex) 불편사항, 개선 아이디어 등', + border: OutlineInputBorder(), + ), + ), + ], + ); + + default: + return const Text('설문 문항 오류', textAlign: TextAlign.center); + } + } +} diff --git a/lib/views/room/finish_private_page.dart b/lib/views/room/finish_private_page.dart index 173eedf..4cf6ac5 100644 --- a/lib/views/room/finish_private_page.dart +++ b/lib/views/room/finish_private_page.dart @@ -36,7 +36,7 @@ class _FinishPrivatePageState extends State { String _roomTitle = ''; DateTime? _startDt; DateTime? _endDt; - int _masterUserSeq = 0; // 방장 user_seq (ADMIN과는 별개) + String _masterUserSeq = '0'; // 방장 user_seq (ADMIN과는 별개) @override void initState() { @@ -70,7 +70,7 @@ class _FinishPrivatePageState extends State { _roomInfo = rInfo; _userMap = uInfo; _roomTitle = rTitle.isNotEmpty ? rTitle : '종료된 방(개인전)'; - _masterUserSeq = mSeq; + _masterUserSeq = mSeq.toString(); if (sdt != null && sdt is String && sdt.contains('T')) { _startDt = DateTime.tryParse(sdt); @@ -154,7 +154,7 @@ class _FinishPrivatePageState extends State { final score = (user['score'] ?? 0) as int; var nickname = user['nickname'] ?? '유저'; final profileImg = user['profile_img'] ?? ''; - final userSeq = user['user_seq'] ?? 0; + final userSeq = user['user_seq'].toString() ?? '0'; final participantType = user['participant_type'] ?? ''; if (_masterUserSeq == userSeq) { diff --git a/lib/views/room/finish_team_page.dart b/lib/views/room/finish_team_page.dart index cb35780..a26c10a 100644 --- a/lib/views/room/finish_team_page.dart +++ b/lib/views/room/finish_team_page.dart @@ -30,7 +30,7 @@ class _FinishTeamPageState extends State { List> _userList = []; String _roomTitle = ''; - int _masterUserSeq = 0; + String _masterUserSeq = '0'; DateTime? _startDt; DateTime? _endDt; @@ -70,7 +70,7 @@ class _FinishTeamPageState extends State { _roomInfo = rInfo; _userMap = uInfo; _roomTitle = rTitle.isNotEmpty ? rTitle : '종료된 팀전'; - _masterUserSeq = mSeq; + _masterUserSeq = mSeq.toString(); if (sdt != null && sdt is String && sdt.contains('T')) { _startDt = DateTime.tryParse(sdt); @@ -233,7 +233,7 @@ class _FinishTeamPageState extends State { final score = (user['score'] ?? 0) as int; var nickname = user['nickname'] ?? '유저'; final profileImg = user['profile_img'] ?? ''; - final userSeq = user['user_seq'] ?? 0; + final userSeq = user['user_seq'].toString() ?? '0'; final participantType = user['participant_type'] ?? ''; if (_masterUserSeq == userSeq) { diff --git a/lib/views/room/main_page.dart b/lib/views/room/main_page.dart index bce3101..dc0a5b3 100644 --- a/lib/views/room/main_page.dart +++ b/lib/views/room/main_page.dart @@ -51,16 +51,13 @@ class _MainPageState extends State { // (A) 메인페이지 들어올 때 전체 FRD 연결 해제 FirebaseDatabase.instance.goOffline(); - // (B) 강제 종료 여부 확인 후 재입장 시도 + // (B) 랜딩 페이지 정보 확인 WidgetsBinding.instance.addPostFrameCallback((_) { - _checkForcedExitStatus(); + _checkLandingMainPageInfo(); }); // (C) 배너 광고 초기화 _initBannerAd(); - - // (D) 설문조사 팝업 표시 - _checkSurveyPopup(); } @override @@ -92,18 +89,6 @@ class _MainPageState extends State { _bannerAd?.load(); } - /// "오늘 하루 보지 않기" 체크 여부 확인 후, 모달 보여줄지 결정 - Future _checkSurveyPopup() async { - final prefs = await SharedPreferences.getInstance(); - final shownToday = prefs.getString('survey_popup_today') ?? 'N'; - if (shownToday == 'N') { - // 아직 오늘은 안 봤으므로 팝업 띄우기 - Future.delayed(Duration.zero, () { - showSurveyDialog(context); - }); - } - } - Future _onWillPop() async { final now = DateTime.now(); if (_lastPressedTime == null || @@ -124,11 +109,11 @@ class _MainPageState extends State { } /// (B) 서버에 "강제 종료 여부" 확인 → 방이 있으면 재입장 - Future _checkForcedExitStatus() async { + Future _checkLandingMainPageInfo() async { try { final Map requestBody = {}; final response = await Api.serverRequest( - uri: '/room/score/enter/running/room', + uri: '/room/score/landing/mainpage/info', body: requestBody, ); @@ -171,6 +156,17 @@ class _MainPageState extends State { ); } } + final surveyYn = (data['survey_yn'] ?? 'N').toString().toUpperCase(); + final joinGameYn = (data['join_game_yn'] ?? 'N').toString().toUpperCase(); + final prefs = await SharedPreferences.getInstance(); + final surveyShownToday = prefs.getString('survey_popup_today') ?? 'N'; + final nickname = (data['nickname'] ?? '').toString(); + if (surveyYn == 'N' && joinGameYn == 'Y' && surveyShownToday == 'N') { + // 설문조사 팝업 표시 + Future.delayed(Duration.zero, () { + showSurveyDialog(context, nickname); + }); + } } else { final msgTitle = resp['response_info']?['msg_title'] ?? '오류'; final msgContent = resp['response_info']?['msg_content'] ?? '강제 종료 여부 확인 실패'; diff --git a/lib/views/room/playing_private_page.dart b/lib/views/room/playing_private_page.dart index 29abb4f..58b88ab 100644 --- a/lib/views/room/playing_private_page.dart +++ b/lib/views/room/playing_private_page.dart @@ -132,9 +132,10 @@ class _PlayingPrivatePageState extends State { } final data = snapshot.value as Map? ?? {}; + print('data111111111 $data'); final roomInfoData = data['roomInfo'] as Map? ?? {}; final userInfoData = data['userInfo'] as Map? ?? {}; - final userListData = data['userList'] as Map?; + final userListData = data['userList'] as Map? ?? {}; // 방 상태 체크 final roomStatus = (roomInfoData['room_status'] ?? 'WAIT').toString().toUpperCase(); @@ -167,15 +168,16 @@ class _PlayingPrivatePageState extends State { _userListMap.clear(); if (userListData != null) { userListData.forEach((k, v) { - _userListMap[k.toString()] = (v == true); + _userListMap[k.toString().replaceAll('_', '')] = (v == true); }); } // 전체 유저 목록 final List> rawList = []; userInfoData.forEach((uSeq, uData) { + uSeq = uSeq.toString().replaceAll('_', ''); // 방장 표시 - if (uSeq.toString() == roomInfoData['master_user_seq'].toString()) { + if (uSeq == roomInfoData['master_user_seq'].toString()) { uData['nickname'] = '★' + (uData['nickname'] ?? '유저'); } else if ((uData['participant_type'] ?? '').toString().toUpperCase() == 'ADMIN') { // 관리자 표시 diff --git a/lib/views/room/playing_team_page.dart b/lib/views/room/playing_team_page.dart index a5c08e7..aaeb567 100644 --- a/lib/views/room/playing_team_page.dart +++ b/lib/views/room/playing_team_page.dart @@ -138,7 +138,7 @@ class _PlayingTeamPageState extends State { final data = snapshot.value as Map? ?? {}; final roomInfoData = data['roomInfo'] as Map? ?? {}; final userInfoData = data['userInfo'] as Map? ?? {}; - final userListData = data['userList'] as Map?; + final userListData = data['userList'] as Map? ?? {}; final roomStatus = (roomInfoData['room_status'] ?? 'WAIT').toString().toUpperCase(); if (roomStatus == 'FINISH') { @@ -169,13 +169,14 @@ class _PlayingTeamPageState extends State { _userListMap.clear(); if (userListData != null) { userListData.forEach((k, v) { - _userListMap[k.toString()] = (v == true); + _userListMap[k.toString().replaceAll('_', '')] = (v == true); }); } // 전체 유저 final List> rawList = []; userInfoData.forEach((uSeq, uData) { + uSeq = uSeq.toString().replaceAll('_', ''); // 방장 표시 if (uSeq.toString() == roomInfoData['master_user_seq'].toString()) { uData['nickname'] = '★' + (uData['nickname'] ?? '유저'); diff --git a/lib/views/room/waiting_room_private_page.dart b/lib/views/room/waiting_room_private_page.dart index 312cb0d..a7faea4 100644 --- a/lib/views/room/waiting_room_private_page.dart +++ b/lib/views/room/waiting_room_private_page.dart @@ -62,6 +62,9 @@ class _WaitingRoomPrivatePageState extends State { // 내 user_seq String mySeq = '0'; + // 준비 버튼 3초 딜레이 + bool _readyButtonEnabled = true; // true: 클릭 가능, false: 클릭 불가 + // ───────────────────────────────────────── // 1시간 카운트다운 // ───────────────────────────────────────── @@ -77,7 +80,7 @@ class _WaitingRoomPrivatePageState extends State { String adUnitId = Config.testAdUnitId; // 방장 SEQ 저장 - String _masterSeqString = ''; + String _masterSeqString = '0'; @override void initState() { @@ -121,12 +124,14 @@ class _WaitingRoomPrivatePageState extends State { Future _initRoomRef() async { final prefs = await SharedPreferences.getInstance(); mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0'; + print('mySeq111111111 $mySeq'); final roomKey = 'korea-${widget.roomSeq}'; _roomRef = FirebaseDatabase.instance.ref('rooms/$roomKey'); // onDisconnect + connect_yn='Y' - final myUserRef = _roomRef.child('userInfo').child(mySeq); + final myUserRef = _roomRef.child('userInfo').child('_${mySeq}'); + print('myUserRef111111111 $myUserRef'); if (_roomRef.child('userList').child(mySeq) == true) { myUserRef.onDisconnect().update({'connect_yn': 'N'}); } @@ -151,7 +156,7 @@ class _WaitingRoomPrivatePageState extends State { final data = snapshot.value as Map? ?? {}; final roomInfoData = data['roomInfo'] as Map? ?? {}; - final userInfoDynamic = data['userInfo']; // 이건 List일 수 있음 + final userInfoDynamic = data['userInfo'] as Map? ?? {}; final roomStatus = (roomInfoData['room_status'] ?? 'WAIT').toString().toUpperCase(); @@ -160,7 +165,7 @@ class _WaitingRoomPrivatePageState extends State { if (userInfoDynamic is Map) { userInfoDynamic.forEach((key, val) { if (val is Map) { - final tempUserSeq = val['user_seq'] ?? '0'; + final tempUserSeq = val['user_seq'].toString() ?? '0'; if (tempUserSeq != '0') { tempList.add({ 'user_seq': tempUserSeq, @@ -190,13 +195,13 @@ class _WaitingRoomPrivatePageState extends State { // 방장 여부 roomMasterYn = 'N'; - final masterSeq = roomInfoData['master_user_seq']; - if (masterSeq != null && masterSeq.toString() == mySeq) { + final masterSeq = roomInfoData['master_user_seq'].toString(); + if (masterSeq != null && masterSeq == mySeq) { roomMasterYn = 'Y'; } if (masterSeq != null) { - _masterSeqString = masterSeq.toString(); + _masterSeqString = masterSeq; } else { _masterSeqString = ''; } @@ -237,7 +242,7 @@ class _WaitingRoomPrivatePageState extends State { } // (D) 내가 목록에서 사라졌는지 => 강퇴 판별 - final amIStillHere = _userList.any((u) => u['user_seq'].toString() == mySeq); + final amIStillHere = _userList.any((u) => (u['user_seq'].toString() ?? '0') == mySeq); if (!amIStillHere && !_kickedOut && roomMasterYn != 'Y') { _kickedOut = true; if (_roomExitYn == 'N') { @@ -363,7 +368,7 @@ class _WaitingRoomPrivatePageState extends State { ), TextButton( onPressed: () { - final myUserRef = _roomRef.child('userInfo').child(mySeq); + final myUserRef = _roomRef.child('userInfo').child('_${mySeq}'); myUserRef.onDisconnect().cancel(); Navigator.pop(context, true); }, @@ -404,7 +409,7 @@ class _WaitingRoomPrivatePageState extends State { Widget _buildTopButtons() { if (_isLoading) return const SizedBox(); - final me = _userList.firstWhere((u) => (u['user_seq'] ?? '0') == mySeq, orElse: () => {}); + final me = _userList.firstWhere((u) => (u['user_seq'].toString() ?? '0') == mySeq, orElse: () => {}); final myReadyYn = (me['ready_yn'] ?? 'N').toString().toUpperCase(); final bool isReady = (myReadyYn == 'Y'); final readyLabel = isReady ? '준비완료' : '준비'; @@ -434,7 +439,7 @@ class _WaitingRoomPrivatePageState extends State { margin: const EdgeInsets.symmetric(horizontal: 4), child: ElevatedButton( style: btnStyle, - onPressed: _onToggleReady, + onPressed: _readyButtonEnabled ? _onToggleReady : null, child: Text(readyLabel), ), ), @@ -470,7 +475,7 @@ class _WaitingRoomPrivatePageState extends State { margin: const EdgeInsets.symmetric(horizontal: 8), child: ElevatedButton( style: btnStyle, - onPressed: _onToggleReady, + onPressed: _readyButtonEnabled ? _onToggleReady : null, child: Text(readyLabel), ), ), @@ -481,17 +486,44 @@ class _WaitingRoomPrivatePageState extends State { } Future _onToggleReady() async { + // (A) 버튼이 비활성화 상태면 리턴 + if (!_readyButtonEnabled) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('잠시 후에 다시 눌러주세요. (3초 대기)'), + duration: Duration(seconds: 1), + ), + ); + } + return; + } + + // (B) 버튼 비활성화 + setState(() { + _readyButtonEnabled = false; + }); + try { - final me = _userList.firstWhere((u) => (u['user_seq'] ?? '0') == mySeq, orElse: () => {}); + final me = _userList.firstWhere((u) => (u['user_seq'].toString() ?? '0') == mySeq, orElse: () => {}); final myReadyYn = (me['ready_yn'] ?? 'N').toString().toUpperCase(); final isReady = (myReadyYn == 'Y'); final newYn = isReady ? 'N' : 'Y'; - final userRef = _roomRef.child('userInfo').child(mySeq); + final userRef = _roomRef.child('userInfo').child('_${mySeq}'); await userRef.update({"ready_yn": newYn}); } catch (e) { - print('READY 설정 실패: $e'); + showResponseDialog(context, '오류', 'READY 설정 실패했습니다.'); } + + // (C) 3초 후 다시 버튼 활성화 + Future.delayed(const Duration(seconds: 3), () { + if (mounted) { + setState(() { + _readyButtonEnabled = true; + }); + } + }); } Future _onOpenRoomSetting() async { @@ -617,7 +649,7 @@ class _WaitingRoomPrivatePageState extends State { Widget _buildPlayerSection() { final playerList = _userList.where((u) { - final t = (u['user_seq'] ?? null); + final t = (u['user_seq'].toString() ?? null); return t != null; }).toList(); // final playerList = _userList; diff --git a/lib/views/room/waiting_room_team_page.dart b/lib/views/room/waiting_room_team_page.dart index 44dc2ce..2bbec22 100644 --- a/lib/views/room/waiting_room_team_page.dart +++ b/lib/views/room/waiting_room_team_page.dart @@ -66,6 +66,9 @@ class _WaitingRoomTeamPageState extends State { String mySeq = '0'; + // 준비 버튼 3초 딜레이 + bool _readyButtonEnabled = true; // true: 클릭 가능, false: 클릭 불가 + // (★) 1시간 카운트다운 Timer? _countdownTimer; Duration _remaining = const Duration(hours: 1); @@ -79,7 +82,7 @@ class _WaitingRoomTeamPageState extends State { String adUnitId = Config.testAdUnitId; // 방장 SEQ 저장 - String _masterSeqString = ''; + String _masterSeqString = '0'; @override void initState() { @@ -99,7 +102,7 @@ class _WaitingRoomTeamPageState extends State { _roomRef = FirebaseDatabase.instance.ref('rooms/$roomKey'); // onDisconnect + connect_yn='Y' - final myUserRef = _roomRef.child('userInfo').child(mySeq); + final myUserRef = _roomRef.child('userInfo').child('_${mySeq}'); if (_roomRef.child('userList').child(mySeq) == true) { myUserRef.onDisconnect().update({'connect_yn': 'N'}); } @@ -154,8 +157,7 @@ class _WaitingRoomTeamPageState extends State { final data = snapshot.value as Map? ?? {}; final roomInfoData = data['roomInfo'] as Map? ?? {}; - // final userInfoData = data['userInfo'] as Map? ?? {}; - final userInfoDynamic = data['userInfo']; // 이건 List일 수 있음 + final userInfoDynamic = data['userInfo'] as Map? ?? {}; final roomStatus = (roomInfoData['room_status'] ?? 'WAIT').toString().toUpperCase(); @@ -163,7 +165,7 @@ class _WaitingRoomTeamPageState extends State { // userList if (userInfoDynamic is Map) { userInfoDynamic.forEach((key, val) { - final tempUserSeq = val['user_seq'] ?? '0'; + final tempUserSeq = val['user_seq'].toString() ?? '0'; if (tempUserSeq != '0') { if (val is Map) { tempList.add({ @@ -202,15 +204,15 @@ class _WaitingRoomTeamPageState extends State { // 방장 roomMasterYn = 'N'; - final masterSeq = roomInfoData['master_user_seq']; - if (masterSeq != null && masterSeq.toString() == mySeq) { + final masterSeq = roomInfoData['master_user_seq'].toString(); + if (masterSeq != null && masterSeq == mySeq) { roomMasterYn = 'Y'; } if (masterSeq != null) { - _masterSeqString = masterSeq.toString(); + _masterSeqString = masterSeq; } else { - _masterSeqString = ''; + _masterSeqString = '0'; } _userList = tempList; @@ -248,7 +250,7 @@ class _WaitingRoomTeamPageState extends State { } // (D) 내가 목록에서 사라졌는지 => 강퇴 판별 - final amIStillHere = _userList.any((u) => u['user_seq'].toString() == mySeq); + final amIStillHere = _userList.any((u) => (u['user_seq'].toString() ?? '0') == mySeq); if (!amIStillHere && !_kickedOut && roomMasterYn != 'Y') { _kickedOut = true; if (_roomExitYn == 'N') { @@ -373,7 +375,7 @@ class _WaitingRoomTeamPageState extends State { ), TextButton( onPressed: () { - final myUserRef = _roomRef.child('userInfo').child(mySeq); + final myUserRef = _roomRef.child('userInfo').child('_${mySeq}'); myUserRef.onDisconnect().cancel(); Navigator.pop(context, true); }, @@ -442,7 +444,7 @@ class _WaitingRoomTeamPageState extends State { margin: const EdgeInsets.symmetric(horizontal: 4), child: ElevatedButton( style: btnStyle, - onPressed: _onToggleReady, + onPressed: _readyButtonEnabled ? _onToggleReady : null, child: Text(readyLabel), ), ), @@ -479,7 +481,7 @@ class _WaitingRoomTeamPageState extends State { margin: const EdgeInsets.symmetric(horizontal: 8), child: ElevatedButton( style: btnStyle, - onPressed: _onToggleReady, + onPressed: _readyButtonEnabled ? _onToggleReady : null, child: Text(readyLabel), ), ), @@ -490,17 +492,44 @@ class _WaitingRoomTeamPageState extends State { } Future _onToggleReady() async { + // (A) 버튼이 비활성화 상태면 리턴 + if (!_readyButtonEnabled) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('잠시 후에 다시 눌러주세요. (3초 대기)'), + duration: Duration(seconds: 1), + ), + ); + } + return; + } + + // (B) 버튼 비활성화 + setState(() { + _readyButtonEnabled = false; + }); + try { final me = _userList.firstWhere((u) => (u['user_seq'].toString() ?? '') == mySeq, orElse: () => {}); final myReadyYn = (me['ready_yn'] ?? 'N').toString().toUpperCase(); final isReady = (myReadyYn == 'Y'); final newYn = isReady ? 'N' : 'Y'; - final userRef = _roomRef.child('userInfo').child(mySeq); + final userRef = _roomRef.child('userInfo').child('_${mySeq}'); await userRef.update({"ready_yn": newYn}); } catch (e) { showResponseDialog(context, '오류', 'READY 설정에 실패했습니다.'); } + + // (C) 3초 후 다시 버튼 활성화 + Future.delayed(const Duration(seconds: 3), () { + if (mounted) { + setState(() { + _readyButtonEnabled = true; + }); + } + }); } Future _onOpenRoomSetting() async { @@ -643,7 +672,7 @@ class _WaitingRoomTeamPageState extends State { Widget _buildTeamSection() { final players = _userList.where((u) { - final t = (u['user_seq'] ?? null); + final t = (u['user_seq'].toString() ?? null); return t != null; }).toList(); // final players = _userList.toList(); diff --git a/pubspec.lock b/pubspec.lock index 03d21e7..03c8918 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.48" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" + url: "https://pub.dev" + source: hosted + version: "2.0.3" + archive: + dependency: transitive + description: + name: archive + sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + args: + dependency: transitive + description: + name: args + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + url: "https://pub.dev" + source: hosted + version: "2.6.0" async: dependency: transitive description: @@ -33,6 +57,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" + url: "https://pub.dev" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -65,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.6" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" cupertino_icons: dependency: "direct main" description: @@ -206,6 +254,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_launcher_icons: + dependency: "direct main" + description: + name: flutter_launcher_icons + sha256: "02dcaf49d405f652b7160e882bacfc02cb497041bb2eab2a49b1c393cf9aac12" + url: "https://pub.dev" + source: hosted + version: "0.12.0" flutter_lints: dependency: "direct dev" description: @@ -214,6 +270,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + flutter_native_splash: + dependency: "direct main" + description: + name: flutter_native_splash + sha256: "7062602e0dbd29141fb8eb19220b5871ca650be5197ab9c1f193a28b17537bc7" + url: "https://pub.dev" + source: hosted + version: "2.4.4" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -288,6 +352,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.10.2+1" + html: + dependency: transitive + description: + name: html + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" + url: "https://pub.dev" + source: hosted + version: "0.15.5" http: dependency: "direct main" description: @@ -304,6 +376,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.1" + image: + dependency: transitive + description: + name: image + sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6" + url: "https://pub.dev" + source: hosted + version: "4.5.2" image_picker: dependency: "direct main" description: @@ -376,6 +456,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" leak_tracker: dependency: transitive description: @@ -472,6 +560,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" platform: dependency: transitive description: @@ -488,6 +584,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + posix: + dependency: transitive + description: + name: posix + sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + url: "https://pub.dev" + source: hosted + version: "6.0.1" shared_preferences: dependency: "direct main" description: @@ -605,6 +709,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" vector_math: dependency: transitive description: @@ -669,6 +781,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" sdks: dart: ">=3.6.0 <4.0.0" flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index ea4e4b0..77d4b13 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,11 +24,15 @@ dependencies: google_sign_in: ^5.4.0 cupertino_icons: ^1.0.8 fluttertoast: ^8.0.9 + flutter_launcher_icons: ^0.12.0 + flutter_native_splash: ^2.2.15 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 + flutter_launcher_icons: ^0.12.0 + flutter_native_splash: ^2.2.15 # ─────────────────────────────────── # 플러터 섹션 @@ -45,3 +49,15 @@ flutter: - assets/images/icons8-google-logo-96.png - assets/images/icons8-google-logo-144.png - assets/images/icons8-google-logo-192.png + +flutter_icons: + android: true + ios: true + + image_path: "assets/icons/allscore_icon.png" + +flutter_native_splash: + color: "#ffffff" + image: assets/icons/allscore_icon.png + android: true + ios: true diff --git a/web/index.html b/web/index.html index 5cacd5a..439b20d 100644 --- a/web/index.html +++ b/web/index.html @@ -1,6 +1,4 @@ - - - + - + allscore_app + + + - - - + + + + + + + + + \ No newline at end of file diff --git a/web/splash/img/dark-1x.png b/web/splash/img/dark-1x.png new file mode 100644 index 0000000..9668894 Binary files /dev/null and b/web/splash/img/dark-1x.png differ diff --git a/web/splash/img/dark-2x.png b/web/splash/img/dark-2x.png new file mode 100644 index 0000000..341554c Binary files /dev/null and b/web/splash/img/dark-2x.png differ diff --git a/web/splash/img/dark-3x.png b/web/splash/img/dark-3x.png new file mode 100644 index 0000000..e39e843 Binary files /dev/null and b/web/splash/img/dark-3x.png differ diff --git a/web/splash/img/dark-4x.png b/web/splash/img/dark-4x.png new file mode 100644 index 0000000..0464e12 Binary files /dev/null and b/web/splash/img/dark-4x.png differ diff --git a/web/splash/img/light-1x.png b/web/splash/img/light-1x.png new file mode 100644 index 0000000..9668894 Binary files /dev/null and b/web/splash/img/light-1x.png differ diff --git a/web/splash/img/light-2x.png b/web/splash/img/light-2x.png new file mode 100644 index 0000000..341554c Binary files /dev/null and b/web/splash/img/light-2x.png differ diff --git a/web/splash/img/light-3x.png b/web/splash/img/light-3x.png new file mode 100644 index 0000000..e39e843 Binary files /dev/null and b/web/splash/img/light-3x.png differ diff --git a/web/splash/img/light-4x.png b/web/splash/img/light-4x.png new file mode 100644 index 0000000..0464e12 Binary files /dev/null and b/web/splash/img/light-4x.png differ