diff --git a/lib/dialogs/room_setting_finish_dialog.dart b/lib/dialogs/room_setting_finish_dialog.dart index bc61d85..5ca3623 100644 --- a/lib/dialogs/room_setting_finish_dialog.dart +++ b/lib/dialogs/room_setting_finish_dialog.dart @@ -17,7 +17,16 @@ class RoomSettingFinishDialog extends StatelessWidget { final String openYn = (roomInfo['open_yn'] ?? 'Y') as String; final int maxPeople = (roomInfo['number_of_people'] ?? 0) as int; final int runningTime = (roomInfo['running_time'] ?? 0) as int; - final String scoreOpen = (roomInfo['score_open_range'] ?? 'ALL') as String; + final String tempScoreOpen = (roomInfo['score_open_range'] ?? 'ALL') as String; + var scoreOpen = ''; + + if (tempScoreOpen == 'ALL' || tempScoreOpen == 'all') { + scoreOpen = '전체 공개'; + } else if (tempScoreOpen == 'TEAM' || tempScoreOpen == 'team') { + scoreOpen = '팀 공개'; + } else { + scoreOpen = '개인 공개'; + } final String openLabel = (openYn == 'Y') ? '공개' : '비공개'; diff --git a/lib/dialogs/survey_dialog.dart b/lib/dialogs/survey_dialog.dart new file mode 100644 index 0000000..c45e744 --- /dev/null +++ b/lib/dialogs/survey_dialog.dart @@ -0,0 +1,111 @@ +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('여기는 설문 페이지입니다 (임시).'), + ), + ); + } +} + +/// 팝업(모달) 자체를 보여주는 함수 +Future showSurveyDialog(BuildContext context) async { + showDialog( + context: context, + barrierDismissible: false, // 바깥 영역 터치로 닫기 방지 + builder: (_) => const SurveyDialog(), + ); +} + +/// 실제 AlertDialog 형태의 위젯 +class SurveyDialog extends StatefulWidget { + const SurveyDialog({Key? key}) : super(key: key); + + @override + State createState() => _SurveyDialogState(); +} + +class _SurveyDialogState extends State { + bool _todayNotSee = false; // "오늘 하루 보지 않기" 체크 여부 + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('설문 참여 안내'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + '안녕하세요, "올스코어" 앱을 이용해주셔서 감사합니다.\n\n' + '더 나은 서비스 제공을 위해 간단한 설문조사를 준비했습니다.\n' + '설문조사에 참여해주시면 앱 발전에 큰 도움이 됩니다!\n' + '(약 1분 소요)', + ), + const SizedBox(height: 16), + // "오늘 하루 보지 않기" 체크박스 + Row( + children: [ + Checkbox( + value: _todayNotSee, + onChanged: (val) { + setState(() { + _todayNotSee = val ?? false; + }); + }, + ), + const Text('오늘 하루 보지 않기'), + ], + ), + ], + ), + ), + actions: [ + // "닫기" 버튼 + TextButton( + onPressed: () async { + // 오늘 하루 보지 않기를 체크했다면, SharedPreferences 저장 + if (_todayNotSee) { + final prefs = await SharedPreferences.getInstance(); + // 예: survey_popup_today = 'Y' + await prefs.setString('survey_popup_today', 'Y'); + } + Navigator.pop(context); // 팝업 닫기 + }, + style: TextButton.styleFrom(backgroundColor: Colors.grey), + child: const Text('닫기', style: TextStyle(color: Colors.white)), + ), + // "설문 참여" 버튼 + TextButton( + onPressed: () async { + // 오늘 하루 보지 않기를 체크했다면, SharedPreferences 저장 + if (_todayNotSee) { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('survey_popup_today', 'Y'); + } + Navigator.pop(context); // 팝업 닫고 + // 임시 설문 페이지로 이동 + Navigator.push( + context, + MaterialPageRoute(builder: (_) => const SurveyPage()), + ); + }, + style: TextButton.styleFrom(backgroundColor: Colors.black), + child: const Text('설문 참여', style: TextStyle(color: Colors.white)), + ), + ], + ); + } +} diff --git a/lib/views/room/finish_private_page.dart b/lib/views/room/finish_private_page.dart index 50a0dc0..173eedf 100644 --- a/lib/views/room/finish_private_page.dart +++ b/lib/views/room/finish_private_page.dart @@ -6,14 +6,16 @@ import '../../dialogs/response_dialog.dart'; import '../../dialogs/room_setting_finish_dialog.dart'; import '../../dialogs/user_info_finish_dialog.dart'; +import 'main_page.dart'; + class FinishPrivatePage extends StatefulWidget { final int roomSeq; - final bool fromPlayingPage; // 만약 대기/진행중에서 넘어온 경우 => 뒤로가기 시 메인으로 + final String enterType; // 대기/진행중에서 넘어온 경우 => 뒤로가기 시 메인으로 const FinishPrivatePage({ Key? key, required this.roomSeq, - this.fromPlayingPage = false, + required this.enterType, }) : super(key: key); @override @@ -28,10 +30,8 @@ class _FinishPrivatePageState extends State { // userSeq → { user_seq, nickname, participant_type, score, ... } Map _userMap = {}; - // 리스트로 만든 (관리자 제외) 참가자 목록 (점수 내림차순) + // 리스트로 만든 참가자 목록 (점수 내림차순) List> _playerList = []; - // 별도 사회자(ADMIN) 목록 (개인전이라 1명이거나 없을 수 있음) - List> _adminList = []; String _roomTitle = ''; DateTime? _startDt; @@ -87,17 +87,7 @@ class _FinishPrivatePageState extends State { tempList.add(Map.from(val)); }); - // (1) 사회자(ADMIN) 분리 - final adminList = tempList.where((u) { - final pType = (u['participant_type'] ?? '').toString().toUpperCase(); - return pType == 'ADMIN'; - }).toList(); - - // (2) 플레이어 목록 (ADMIN 제외) & 점수 내림차순 - final playerList = tempList.where((u) { - final pType = (u['participant_type'] ?? '').toString().toUpperCase(); - return pType != 'ADMIN'; - }).toList(); + final playerList = tempList.toList(); // 점수 내림차순 정렬 playerList.sort((a, b) { @@ -107,7 +97,6 @@ class _FinishPrivatePageState extends State { }); setState(() { - _adminList = adminList; _playerList = playerList; _isLoading = false; }); @@ -128,9 +117,9 @@ class _FinishPrivatePageState extends State { /// (B) 뒤로가기 Future _onWillPop() async { - if (widget.fromPlayingPage) { - // 진행중/대기중 등에서 넘어왔다면 => 메인으로 - Navigator.popUntil(context, (route) => route.isFirst); + if (widget.enterType == 'game') { + // 진행중에서 넘어왔다면 => 메인으로 + Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false); } else { // 검색 등에서 왔으면 => 한 단계 pop Navigator.pop(context); @@ -163,9 +152,18 @@ class _FinishPrivatePageState extends State { /// - 1등/2등/3등 금/은/동 메달 Widget _buildPlayerItem(Map user, int index) { final score = (user['score'] ?? 0) as int; - final nickname = user['nickname'] ?? '유저'; + var nickname = user['nickname'] ?? '유저'; final profileImg = user['profile_img'] ?? ''; final userSeq = user['user_seq'] ?? 0; + final participantType = user['participant_type'] ?? ''; + + if (_masterUserSeq == userSeq) { + // 방장 표시 + nickname = '★' + nickname; + } else if (participantType == 'ADMIN') { + // 관리자 표시 + nickname = '☆' + nickname; + } Widget medal = const SizedBox(); if (index == 0) { @@ -211,37 +209,6 @@ class _FinishPrivatePageState extends State { ); } - /// 사회자 목록 (보통 1명 예상) - Widget _buildAdminItem(Map admin) { - final nickname = admin['nickname'] ?? '사회자'; - final profileImg = admin['profile_img'] ?? ''; - return GestureDetector( - onTap: () => _onTapUser(admin), - child: Row( - children: [ - Container( - width: 36, height: 36, - margin: const EdgeInsets.only(right: 8), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all(color: Colors.deepPurple), - ), - child: ClipOval( - child: (profileImg.isNotEmpty) - ? Image.network( - 'https://eldsoft.com:8097/images$profileImg', - fit: BoxFit.cover, - errorBuilder: (_, __, ___) => const Center(child: Text('ERR')), - ) - : const Center(child: Text('No\nImg', textAlign: TextAlign.center, style: TextStyle(fontSize: 10))), - ), - ), - Text(nickname, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.deepPurple)), - ], - ), - ); - } - /// 사용자 클릭 -> 새 유저 정보 모달 Future _onTapUser(Map userData) async { // user_info_finish_dialog.dart (새 모달) @@ -290,25 +257,6 @@ class _FinishPrivatePageState extends State { ), const SizedBox(height: 16), - // (B) 사회자 목록 - if (_adminList.isNotEmpty) ...[ - Container( - width: double.infinity, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - border: Border.all(color: Colors.deepPurple), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - const Text('사회자: ', style: TextStyle(fontSize: 14, color: Colors.deepPurple)), - ..._adminList.map(_buildAdminItem), - ], - ), - ), - const SizedBox(height: 16), - ], - // (C) 참가자 목록 ListView.builder( primary: false, diff --git a/lib/views/room/finish_team_page.dart b/lib/views/room/finish_team_page.dart index 1d5d78c..cb35780 100644 --- a/lib/views/room/finish_team_page.dart +++ b/lib/views/room/finish_team_page.dart @@ -6,14 +6,16 @@ import '../../dialogs/response_dialog.dart'; import '../../dialogs/room_setting_finish_dialog.dart'; import '../../dialogs/user_info_finish_dialog.dart'; +import 'main_page.dart'; + class FinishTeamPage extends StatefulWidget { final int roomSeq; - final bool fromPlayingPage; // 진행중에서 넘어왔는지 여부 + final String enterType; // 대기/진행중에서 넘어온 경우 => 뒤로가기 시 메인으로 const FinishTeamPage({ Key? key, required this.roomSeq, - this.fromPlayingPage = false, + required this.enterType, }) : super(key: key); @override @@ -37,8 +39,6 @@ class _FinishTeamPageState extends State { // 팀별 점수 Map _teamScoreMap = {}; - // 별도 사회자 목록 - List> _adminList = []; @override void initState() { @@ -86,17 +86,8 @@ class _FinishTeamPageState extends State { tempList.add(Map.from(val)); }); - // (1) 사회자(ADMIN) 분리 - final adminList = tempList.where((u) { - final pType = (u['participant_type'] ?? '').toString().toUpperCase(); - return pType == 'ADMIN'; - }).toList(); - // (2) 일반 참가자 - final players = tempList.where((u) { - final pType = (u['participant_type'] ?? '').toString().toUpperCase(); - return pType != 'ADMIN'; - }).toList(); + final players = tempList.toList(); // (3) 팀명별 분류 + 점수 합 final Map>> tMap = {}; @@ -138,7 +129,6 @@ class _FinishTeamPageState extends State { } setState(() { - _adminList = adminList; _userList = tempList; // 전체 필요하면 보관 _teamMap = finalTeamMap; _teamScoreMap = finalScoreMap; @@ -160,8 +150,8 @@ class _FinishTeamPageState extends State { } Future _onWillPop() async { - if (widget.fromPlayingPage) { - Navigator.popUntil(context, (route) => route.isFirst); + if (widget.enterType == 'game') { + Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false); } else { Navigator.pop(context); } @@ -241,8 +231,18 @@ class _FinishTeamPageState extends State { /// 팀 멤버 표시 Widget _buildTeamMember(Map user) { final score = (user['score'] ?? 0) as int; - final nickname = user['nickname'] ?? '유저'; + var nickname = user['nickname'] ?? '유저'; final profileImg = user['profile_img'] ?? ''; + final userSeq = user['user_seq'] ?? 0; + final participantType = user['participant_type'] ?? ''; + + if (_masterUserSeq == userSeq) { + // 방장 표시 + nickname = '★' + nickname; + } else if (participantType == 'ADMIN') { + // 관리자 표시 + nickname = '☆' + nickname; + } return GestureDetector( onTap: () => _onTapUser(user), @@ -278,63 +278,6 @@ class _FinishTeamPageState extends State { ); } - /// 팀전 사회자 목록 (ADMIN) - Widget _buildAdminList() { - final adminList = _adminList; - if (adminList.isEmpty) return const SizedBox(); - - return Container( - width: double.infinity, - margin: const EdgeInsets.only(top: 16), - decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color: Colors.deepPurple), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - children: [ - Container( - color: Colors.black, - width: double.infinity, - padding: const EdgeInsets.all(8), - child: const Center( - child: Text('사회자', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)), - ), - ), - ListView.builder( - shrinkWrap: true, - primary: false, - itemCount: adminList.length, - itemBuilder: (ctx, i) { - final user = adminList[i]; - return _buildAdminItem(user); - }, - ), - ], - ), - ); - } - - Widget _buildAdminItem(Map user) { - final nickname = user['nickname'] ?? '사회자'; - final profileImg = user['profile_img'] ?? ''; - - return ListTile( - onTap: () => _onTapUser(user), - leading: CircleAvatar( - backgroundColor: Colors.white, - backgroundImage: (profileImg.isNotEmpty) - ? NetworkImage('https://eldsoft.com:8097/images$profileImg') - : null, - child: (profileImg.isEmpty) - ? const Text('NoImg', style: TextStyle(fontSize: 10)) - : null, - ), - title: Text(nickname), - subtitle: const Text('사회자'), - ); - } - Future _onTapUser(Map userData) async { // 새 유저 정보 모달 await showDialog( @@ -388,8 +331,6 @@ class _FinishTeamPageState extends State { for (int i = 0; i < teamNames.length; i++) _buildTeamBox(teamNames[i], i), - // 사회자 목록 - _buildAdminList(), ], ), ), diff --git a/lib/views/room/main_page.dart b/lib/views/room/main_page.dart index 63acaa5..bce3101 100644 --- a/lib/views/room/main_page.dart +++ b/lib/views/room/main_page.dart @@ -22,6 +22,9 @@ import 'package:fluttertoast/fluttertoast.dart'; // 뒤로가기 안내 문구 // 설정 import '../../config/config.dart'; +// 설문조사 +import '../../dialogs/survey_dialog.dart'; + class MainPage extends StatefulWidget { const MainPage({Key? key}) : super(key: key); @@ -55,6 +58,9 @@ class _MainPageState extends State { // (C) 배너 광고 초기화 _initBannerAd(); + + // (D) 설문조사 팝업 표시 + _checkSurveyPopup(); } @override @@ -86,6 +92,18 @@ 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 || diff --git a/lib/views/room/playing_private_page.dart b/lib/views/room/playing_private_page.dart index 13bd00e..29abb4f 100644 --- a/lib/views/room/playing_private_page.dart +++ b/lib/views/room/playing_private_page.dart @@ -143,7 +143,7 @@ class _PlayingPrivatePageState extends State { if (mounted) { Navigator.pushAndRemoveUntil( context, - MaterialPageRoute(builder: (_) => FinishPrivatePage(roomSeq: widget.roomSeq)), + MaterialPageRoute(builder: (_) => FinishPrivatePage(roomSeq: widget.roomSeq, enterType: 'game')), (route) => false, ); } @@ -175,9 +175,12 @@ class _PlayingPrivatePageState extends State { final List> rawList = []; userInfoData.forEach((uSeq, uData) { // 방장 표시 - if (uSeq.toString() == roomInfoData['master_user_seq'].toString()) uData['nickname'] = '★' + (uData['nickname'] ?? '유저'); - // 관리자 표시 - if ((uData['participant_type'] ?? '').toString().toUpperCase() == 'ADMIN') uData['nickname'] = '☆' + (uData['nickname'] ?? '유저'); + if (uSeq.toString() == roomInfoData['master_user_seq'].toString()) { + uData['nickname'] = '★' + (uData['nickname'] ?? '유저'); + } else if ((uData['participant_type'] ?? '').toString().toUpperCase() == 'ADMIN') { + // 관리자 표시 + uData['nickname'] = '☆' + (uData['nickname'] ?? '유저'); + } rawList.add({ 'user_seq': uSeq, 'participant_type': (uData['participant_type'] ?? '').toString().toUpperCase(), @@ -222,6 +225,7 @@ class _PlayingPrivatePageState extends State { MaterialPageRoute( builder: (_) => FinishPrivatePage( roomSeq: widget.roomSeq, + enterType: 'game', ), ), (route) => false, diff --git a/lib/views/room/playing_team_page.dart b/lib/views/room/playing_team_page.dart index 6129842..a5c08e7 100644 --- a/lib/views/room/playing_team_page.dart +++ b/lib/views/room/playing_team_page.dart @@ -146,7 +146,7 @@ class _PlayingTeamPageState extends State { if (mounted) { Navigator.pushAndRemoveUntil( context, - MaterialPageRoute(builder: (_) => FinishTeamPage(roomSeq: widget.roomSeq)), + MaterialPageRoute(builder: (_) => FinishTeamPage(roomSeq: widget.roomSeq, enterType: 'game')), (route) => false, ); } @@ -253,6 +253,7 @@ class _PlayingTeamPageState extends State { MaterialPageRoute( builder: (_) => FinishTeamPage( roomSeq: widget.roomSeq, + enterType: 'game', ), ), (route) => false, diff --git a/lib/views/room/room_search_home_page.dart b/lib/views/room/room_search_home_page.dart index a73fdc1..358cdec 100644 --- a/lib/views/room/room_search_home_page.dart +++ b/lib/views/room/room_search_home_page.dart @@ -1,12 +1,61 @@ import 'package:flutter/material.dart'; import 'room_search_list_page.dart'; -/// 방 검색 홈 화면 -/// - "대기중/진행중/종료" 버튼 3개로 구분 -/// - 버튼 누르면 RoomSearchListPage로 이동 + 상태값 전달 -class RoomSearchHomePage extends StatelessWidget { +// 설정 +import '../../config/config.dart'; + +// 광고 +import 'package:google_mobile_ads/google_mobile_ads.dart'; // ★ AdMob 패키지 + +class RoomSearchHomePage extends StatefulWidget { const RoomSearchHomePage({Key? key}) : super(key: key); + @override + State createState() => _RoomSearchHomePageState(); +} + +class _RoomSearchHomePageState extends State { + BannerAd? _bannerAd; + bool _isBannerReady = false; // 광고 로드 완료 여부 + String adUnitId = Config.testAdUnitId; + + @override + void initState() { + super.initState(); + + // (C) 배너 광고 초기화 + _initBannerAd(); + } + + @override + void dispose() { + _bannerAd?.dispose(); + super.dispose(); + } + + /// 배너 광고 초기화 + void _initBannerAd() { + _bannerAd = BannerAd( + size: AdSize.banner, // 일반 배너 사이즈 + // adUnitId: 'ca-app-pub-3940256099942544/6300978111' (테스트용) + adUnitId: adUnitId, // 실제/테스트 배너 광고 단위 ID + listener: BannerAdListener( + onAdLoaded: (Ad ad) { + setState(() => _isBannerReady = true); + debugPrint('배너 광고 로드 완료'); + }, + onAdFailedToLoad: (Ad ad, LoadAdError err) { + debugPrint('배너 광고 로드 실패: $err'); + ad.dispose(); + }, + ), + request: const AdRequest(), + ); + + // load() 호출로 광고 요청 + _bannerAd?.load(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -23,13 +72,14 @@ class RoomSearchHomePage extends StatelessWidget { ), // 화면 하단 광고 영역 - bottomNavigationBar: Container( - height: 50, - color: Colors.grey.shade400, - child: const Center( - child: Text('구글 광고', style: TextStyle(color: Colors.black)), - ), - ), + bottomNavigationBar: _isBannerReady && _bannerAd != null + ? Container( + color: Colors.white, + width: _bannerAd!.size.width.toDouble(), + height: _bannerAd!.size.height.toDouble(), + child: AdWidget(ad: _bannerAd!), + ) + : SizedBox.shrink(), // 로딩 전엔 빈 공간 or 원하는 위젯 // 본문: 중앙에 3개 버튼 (대기중 / 진행중 / 종료) body: Center( diff --git a/lib/views/room/room_search_list_page.dart b/lib/views/room/room_search_list_page.dart index e72348a..c3792c4 100644 --- a/lib/views/room/room_search_list_page.dart +++ b/lib/views/room/room_search_list_page.dart @@ -10,6 +10,12 @@ import '../../dialogs/room_detail_dialog.dart'; import '../room/finish_private_page.dart'; import '../room/finish_team_page.dart'; +// 설정 +import '../../config/config.dart'; + +// 광고 +import 'package:google_mobile_ads/google_mobile_ads.dart'; // ★ AdMob 패키지 + class RoomSearchListPage extends StatefulWidget { final String roomStatus; // WAIT / RUNNING / FINISH @@ -30,6 +36,11 @@ class _RoomSearchListPageState extends State { final int _pageSize = 10; late ScrollController _scrollController; + + // 배너 광고 관련 변수 + BannerAd? _bannerAd; + bool _isBannerReady = false; // 광고 로드 완료 여부 + String adUnitId = Config.testAdUnitId; @override void initState() { @@ -37,6 +48,9 @@ class _RoomSearchListPageState extends State { _scrollController = ScrollController()..addListener(_onScroll); _fetchRoomList(isRefresh: true); + + // (C) 배너 광고 초기화 + _initBannerAd(); } @override @@ -44,9 +58,33 @@ class _RoomSearchListPageState extends State { _scrollController.removeListener(_onScroll); _scrollController.dispose(); _searchController.dispose(); + _bannerAd?.dispose(); super.dispose(); } + /// 배너 광고 초기화 + void _initBannerAd() { + _bannerAd = BannerAd( + size: AdSize.banner, // 일반 배너 사이즈 + // adUnitId: 'ca-app-pub-3940256099942544/6300978111' (테스트용) + adUnitId: adUnitId, // 실제/테스트 배너 광고 단위 ID + listener: BannerAdListener( + onAdLoaded: (Ad ad) { + setState(() => _isBannerReady = true); + debugPrint('배너 광고 로드 완료'); + }, + onAdFailedToLoad: (Ad ad, LoadAdError err) { + debugPrint('배너 광고 로드 실패: $err'); + ad.dispose(); + }, + ), + request: const AdRequest(), + ); + + // load() 호출로 광고 요청 + _bannerAd?.load(); + } + void _onScroll() { if (!_scrollController.hasClients) return; final thresholdPixels = 200; @@ -161,7 +199,7 @@ class _RoomSearchListPageState extends State { MaterialPageRoute( builder: (_) => FinishPrivatePage( roomSeq: roomSeq, - fromPlayingPage: false, // ← 검색에서 왔으므로 false + enterType: 'search', ), ), ); @@ -171,7 +209,7 @@ class _RoomSearchListPageState extends State { MaterialPageRoute( builder: (_) => FinishTeamPage( roomSeq: roomSeq, - fromPlayingPage: false, + enterType: 'search', ), ), ); @@ -199,6 +237,15 @@ class _RoomSearchListPageState extends State { onPressed: () => Navigator.pop(context), ), ), + // 화면 하단 광고 영역 + bottomNavigationBar: _isBannerReady && _bannerAd != null + ? Container( + color: Colors.white, + width: _bannerAd!.size.width.toDouble(), + height: _bannerAd!.size.height.toDouble(), + child: AdWidget(ad: _bannerAd!), + ) + : SizedBox.shrink(), // 로딩 전엔 빈 공간 or 원하는 위젯 body: Column( children: [ // 검색창 @@ -232,21 +279,6 @@ class _RoomSearchListPageState extends State { ? const Center(child: CircularProgressIndicator()) : _buildRoomListView(), ), - - Container( - height: 60, - color: Colors.white, - child: Center( - child: Container( - height: 50, - width: 300, - color: Colors.grey.shade400, - child: const Center( - child: Text('구글 광고', style: TextStyle(color: Colors.black)), - ), - ), - ), - ), ], ), ); diff --git a/lib/views/room/waiting_room_private_page.dart b/lib/views/room/waiting_room_private_page.dart index 1eacda7..312cb0d 100644 --- a/lib/views/room/waiting_room_private_page.dart +++ b/lib/views/room/waiting_room_private_page.dart @@ -333,7 +333,7 @@ class _WaitingRoomPrivatePageState extends State { } /// 뒤로가기 → 방 나가기 - Future _onLeaveRoom() async { + Future _onLeaveRoom() async { if (roomMasterYn == 'Y') { // 방장 final confirm = await showDialog( @@ -378,7 +378,7 @@ class _WaitingRoomPrivatePageState extends State { ); }, ); - if (confirm != true) return; + if (confirm != true) return false; // leave API setState(() {_roomExitYn = 'Y';}); @@ -388,6 +388,7 @@ class _WaitingRoomPrivatePageState extends State { setState(() {_roomExitYn = 'Y';}); await _requestLeaveRoom(); } + return false; } int _toInt(dynamic val, int defaultVal) { @@ -557,9 +558,11 @@ class _WaitingRoomPrivatePageState extends State { // 남은시간 (기본: 60:00 ~ 0:00) final countdownStr = _formatDuration(_remaining); - return Scaffold( - backgroundColor: Colors.white, - appBar: AppBar( + return WillPopScope( + onWillPop: () => _onLeaveRoom(), + child: Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( backgroundColor: Colors.black, elevation: 0, // 방 제목 + 남은시간 표시 @@ -580,7 +583,7 @@ class _WaitingRoomPrivatePageState extends State { ), leading: IconButton( icon: const Icon(Icons.arrow_back_ios, color: Colors.white), - onPressed: _onLeaveRoom, + onPressed: () => _onLeaveRoom(), ), ), bottomNavigationBar: _isBannerReady && _bannerAd != null @@ -602,43 +605,16 @@ class _WaitingRoomPrivatePageState extends State { _buildTopButtons(), const SizedBox(height: 20), - // const Text('사회자', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), - // const SizedBox(height: 8), - // _buildAdminSection(), - // const SizedBox(height: 20), - const Text('참가자', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 8), _buildPlayerSection(), ], ), ), + ), ); } - // Widget _buildAdminSection() { - // final adminList = _userList.where((u) { - // final t = (u['participant_type'] ?? '').toString().toUpperCase(); - // return t == 'ADMIN'; - // }).toList(); - - // return Container( - // padding: const EdgeInsets.all(8), - // decoration: BoxDecoration( - // color: Colors.white, - // border: Border.all(color: Colors.black), - // borderRadius: BorderRadius.circular(8), - // ), - // child: adminList.isEmpty - // ? const Text('사회자가 없습니다.') - // : Wrap( - // spacing: 16, - // runSpacing: 8, - // children: adminList.map(_buildSeat).toList(), - // ), - // ); - // } - Widget _buildPlayerSection() { final playerList = _userList.where((u) { final t = (u['user_seq'] ?? null); diff --git a/lib/views/room/waiting_room_team_page.dart b/lib/views/room/waiting_room_team_page.dart index b9ff47e..44dc2ce 100644 --- a/lib/views/room/waiting_room_team_page.dart +++ b/lib/views/room/waiting_room_team_page.dart @@ -344,7 +344,7 @@ class _WaitingRoomTeamPageState extends State { } // 뒤로가기 -> 방 나가기 - Future _onLeaveRoom() async { + Future _onLeaveRoom() async { if (roomMasterYn == 'Y') { final confirm = await showDialog( context: context, @@ -388,7 +388,7 @@ class _WaitingRoomTeamPageState extends State { ); }, ); - if (confirm != true) return; + if (confirm != true) return false; // leave API setState(() {_roomExitYn = 'Y';}); @@ -397,6 +397,7 @@ class _WaitingRoomTeamPageState extends State { setState(() {_roomExitYn = 'Y';}); await _requestLeaveRoom(); } + return false; } int _toInt(dynamic val, int defaultVal) { @@ -581,9 +582,11 @@ class _WaitingRoomTeamPageState extends State { Widget build(BuildContext context) { final countdownStr = _formatDuration(_remaining); - return Scaffold( - backgroundColor: Colors.white, - appBar: AppBar( + return WillPopScope( + onWillPop: () => _onLeaveRoom(), + child: Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( backgroundColor: Colors.black, elevation: 0, // 방 제목 + 남은시간 @@ -604,7 +607,7 @@ class _WaitingRoomTeamPageState extends State { ), leading: IconButton( icon: const Icon(Icons.arrow_back_ios, color: Colors.white), - onPressed: _onLeaveRoom, + onPressed: () => _onLeaveRoom(), ), ), bottomNavigationBar: _isBannerReady && _bannerAd != null @@ -625,11 +628,6 @@ class _WaitingRoomTeamPageState extends State { _buildTopButtons(), const SizedBox(height: 20), - // const Text('사회자', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black)), - // const SizedBox(height: 8), - // _buildAdminSection(), - // const SizedBox(height: 20), - const Text('팀별 참가자', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black)), const SizedBox(height: 8), _buildTeamSection(), @@ -639,32 +637,10 @@ class _WaitingRoomTeamPageState extends State { ], ), ), + ), ); } - // Widget _buildAdminSection() { - // final adminList = _userList.where((u) { - // final pType = (u['participant_type'] ?? '').toString().toUpperCase(); - // return pType == 'ADMIN'; - // }).toList(); - - // return Container( - // padding: const EdgeInsets.all(8), - // decoration: BoxDecoration( - // color: Colors.white, - // border: Border.all(color: Colors.black), - // borderRadius: BorderRadius.circular(8), - // ), - // child: adminList.isEmpty - // ? const Text('사회자가 없습니다.', style: TextStyle(color: Colors.black)) - // : Wrap( - // spacing: 16, - // runSpacing: 8, - // children: adminList.map(_buildSeat).toList(), - // ), - // ); - // } - Widget _buildTeamSection() { final players = _userList.where((u) { final t = (u['user_seq'] ?? null);