팀전 대기방 완료

This commit is contained in:
eld_master 2025-01-14 19:32:42 +09:00
parent eab0597573
commit 3cca3401ac
7 changed files with 263 additions and 150 deletions

View File

@ -1 +1 @@
{"flutter":{"platforms":{"android":{"default":{"projectId":"allscore-344c2","appId":"1:70449524223:android:94ffb9ec98e508313e4bca","fileOutput":"android/app/google-services.json"}},"dart":{"lib/firebase_options.dart":{"projectId":"allscore-344c2","configurations":{"android":"1:70449524223:android:94ffb9ec98e508313e4bca","ios":"1:70449524223:ios:98ebdbaa616a807f3e4bca","macos":"1:70449524223:ios:98ebdbaa616a807f3e4bca","web":"1:70449524223:web:e9c27da6646d655f3e4bca","windows":"1:70449524223:web:479dd789b837f54c3e4bca"}}}}}} {"flutter":{"platforms":{"android":{"default":{"projectId":"allscore-29edf","appId":"1:452355332155:android:152995468604d10d13e41e","fileOutput":"android/app/google-services.json"}},"dart":{"lib/firebase_options.dart":{"projectId":"allscore-29edf","configurations":{"android":"1:452355332155:android:152995468604d10d13e41e","ios":"1:452355332155:ios:a7b2fc75e3513e3413e41e","macos":"1:452355332155:ios:a7b2fc75e3513e3413e41e","web":"1:452355332155:web:5407f79d500818e713e41e","windows":"1:452355332155:web:5e08c9caf8d07e2c13e41e"}}}}}}

View File

@ -41,54 +41,57 @@ class DefaultFirebaseOptions {
} }
static const FirebaseOptions web = FirebaseOptions( static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyCnZuHtj5oUe_YS9nv3nlQIKWYCCfYFysU', apiKey: 'AIzaSyCZx2yNaMmMXSFcdNGpl29NerG2PweszWI',
appId: '1:70449524223:web:e9c27da6646d655f3e4bca', appId: '1:452355332155:web:5407f79d500818e713e41e',
messagingSenderId: '70449524223', messagingSenderId: '452355332155',
projectId: 'allscore-344c2', projectId: 'allscore-29edf',
authDomain: 'allscore-344c2.firebaseapp.com', authDomain: 'allscore-29edf.firebaseapp.com',
databaseURL: 'https://allscore-344c2-default-rtdb.asia-southeast1.firebasedatabase.app', databaseURL: 'https://allscore-29edf-default-rtdb.asia-southeast1.firebasedatabase.app',
storageBucket: 'allscore-344c2.firebasestorage.app', storageBucket: 'allscore-29edf.firebasestorage.app',
measurementId: 'G-50Q1W265RY', measurementId: 'G-63H3D8MNM8',
); );
static const FirebaseOptions android = FirebaseOptions( static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyAJEItMxO-TemHGlveSKySG-eNaTD9XJI0', apiKey: 'AIzaSyB6hil7Nrk8wslHDfRNRRyw6rQktY16tTc',
appId: '1:70449524223:android:94ffb9ec98e508313e4bca', appId: '1:452355332155:android:152995468604d10d13e41e',
messagingSenderId: '70449524223', messagingSenderId: '452355332155',
projectId: 'allscore-344c2', projectId: 'allscore-29edf',
databaseURL: 'https://allscore-344c2-default-rtdb.asia-southeast1.firebasedatabase.app', databaseURL: 'https://allscore-29edf-default-rtdb.asia-southeast1.firebasedatabase.app',
storageBucket: 'allscore-344c2.firebasestorage.app', storageBucket: 'allscore-29edf.firebasestorage.app',
); );
static const FirebaseOptions ios = FirebaseOptions( static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyDq2y-BRlthl6BHs4B7FByiUnpyOfPPZQk', apiKey: 'AIzaSyBL1ceaAYfhTpRU2C__HwKkF7cJHhxlpPg',
appId: '1:70449524223:ios:98ebdbaa616a807f3e4bca', appId: '1:452355332155:ios:a7b2fc75e3513e3413e41e',
messagingSenderId: '70449524223', messagingSenderId: '452355332155',
projectId: 'allscore-344c2', projectId: 'allscore-29edf',
databaseURL: 'https://allscore-344c2-default-rtdb.asia-southeast1.firebasedatabase.app', databaseURL: 'https://allscore-29edf-default-rtdb.asia-southeast1.firebasedatabase.app',
storageBucket: 'allscore-344c2.firebasestorage.app', storageBucket: 'allscore-29edf.firebasestorage.app',
androidClientId: '452355332155-t29ceato8o62c9kq9drefe7b6hd1ka1d.apps.googleusercontent.com',
iosClientId: '452355332155-fo49j1u3qfup1sa3gj33bko6q269pqo4.apps.googleusercontent.com',
iosBundleId: 'com.example.allscoreApp', iosBundleId: 'com.example.allscoreApp',
); );
static const FirebaseOptions macos = FirebaseOptions( static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyDq2y-BRlthl6BHs4B7FByiUnpyOfPPZQk', apiKey: 'AIzaSyBL1ceaAYfhTpRU2C__HwKkF7cJHhxlpPg',
appId: '1:70449524223:ios:98ebdbaa616a807f3e4bca', appId: '1:452355332155:ios:a7b2fc75e3513e3413e41e',
messagingSenderId: '70449524223', messagingSenderId: '452355332155',
projectId: 'allscore-344c2', projectId: 'allscore-29edf',
databaseURL: 'https://allscore-344c2-default-rtdb.asia-southeast1.firebasedatabase.app', databaseURL: 'https://allscore-29edf-default-rtdb.asia-southeast1.firebasedatabase.app',
storageBucket: 'allscore-344c2.firebasestorage.app', storageBucket: 'allscore-29edf.firebasestorage.app',
androidClientId: '452355332155-t29ceato8o62c9kq9drefe7b6hd1ka1d.apps.googleusercontent.com',
iosClientId: '452355332155-fo49j1u3qfup1sa3gj33bko6q269pqo4.apps.googleusercontent.com',
iosBundleId: 'com.example.allscoreApp', iosBundleId: 'com.example.allscoreApp',
); );
static const FirebaseOptions windows = FirebaseOptions( static const FirebaseOptions windows = FirebaseOptions(
apiKey: 'AIzaSyCnZuHtj5oUe_YS9nv3nlQIKWYCCfYFysU', apiKey: 'AIzaSyCZx2yNaMmMXSFcdNGpl29NerG2PweszWI',
appId: '1:70449524223:web:479dd789b837f54c3e4bca', appId: '1:452355332155:web:5e08c9caf8d07e2c13e41e',
messagingSenderId: '70449524223', messagingSenderId: '452355332155',
projectId: 'allscore-344c2', projectId: 'allscore-29edf',
authDomain: 'allscore-344c2.firebaseapp.com', authDomain: 'allscore-29edf.firebaseapp.com',
databaseURL: 'https://allscore-344c2-default-rtdb.asia-southeast1.firebasedatabase.app', databaseURL: 'https://allscore-29edf-default-rtdb.asia-southeast1.firebasedatabase.app',
storageBucket: 'allscore-344c2.firebasestorage.app', storageBucket: 'allscore-29edf.firebasestorage.app',
measurementId: 'G-S9J5WDYJZM', measurementId: 'G-MWXRMG174T',
); );
} }

View File

@ -18,7 +18,9 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
// //
await Firebase.initializeApp(); await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// //
MobileAds.instance.initialize(); MobileAds.instance.initialize();

View File

@ -104,10 +104,8 @@ class _LoginPageState extends State<LoginPage> {
listener: BannerAdListener( listener: BannerAdListener(
onAdLoaded: (ad) { onAdLoaded: (ad) {
setState(() => _isBannerReady = true); setState(() => _isBannerReady = true);
print('로그인페이지 배너 광고 로드 완료');
}, },
onAdFailedToLoad: (ad, error) { onAdFailedToLoad: (ad, error) {
print('로그인페이지 배너 광고 로드 실패: $error');
ad.dispose(); ad.dispose();
}, },
), ),
@ -155,7 +153,7 @@ class _LoginPageState extends State<LoginPage> {
await prefs.setString('oauth_type', 'idpw'); await prefs.setString('oauth_type', 'idpw');
await prefs.setBool('auto_login', true); await prefs.setBool('auto_login', true);
await prefs.setString('jwt_token', resp['auth']['token'].toString()); await prefs.setString('jwt_token', resp['auth']['token'].toString());
await prefs.setString('user_seq', resp['auth']['user_seq'].toString()); await prefs.setInt('my_user_seq', resp['auth']['user_seq']);
// //
if (!mounted) return; if (!mounted) return;
@ -225,7 +223,7 @@ class _LoginPageState extends State<LoginPage> {
await prefs.setString('oauth_type', 'google'); await prefs.setString('oauth_type', 'google');
await prefs.setBool('auto_login', true); await prefs.setBool('auto_login', true);
await prefs.setString('jwt_token', resp['auth']['token'].toString()); await prefs.setString('jwt_token', resp['auth']['token'].toString());
await prefs.setString('user_seq', resp['auth']['user_seq'].toString()); await prefs.setInt('my_user_seq', resp['auth']['user_seq']);
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
MaterialPageRoute(builder: (_) => const MainPage()), MaterialPageRoute(builder: (_) => const MainPage()),

View File

@ -348,7 +348,7 @@ class _CreateRoomPageState extends State<CreateRoomPage> {
// //
if (_isTeamGame) { if (_isTeamGame) {
Navigator.pushReplacement( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => WaitingRoomTeamPage( builder: (_) => WaitingRoomTeamPage(
@ -356,9 +356,10 @@ class _CreateRoomPageState extends State<CreateRoomPage> {
roomType: 'team', roomType: 'team',
), ),
), ),
(route) => false,
); );
} else { } else {
Navigator.pushReplacement( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => WaitingRoomPrivatePage( builder: (_) => WaitingRoomPrivatePage(
@ -366,6 +367,7 @@ class _CreateRoomPageState extends State<CreateRoomPage> {
roomType: 'private', roomType: 'private',
), ),
), ),
(route) => false,
); );
} }
} else { } else {
@ -437,7 +439,6 @@ class _CreateRoomPageState extends State<CreateRoomPage> {
return {'result': 'FAIL'}; return {'result': 'FAIL'};
} }
} catch (e) { } catch (e) {
print('serverResponse 오류: $e');
return {'result': 'FAIL'}; return {'result': 'FAIL'};
} }
} }

View File

@ -19,6 +19,9 @@ import '../../dialogs/response_dialog.dart';
// //
import 'package:fluttertoast/fluttertoast.dart'; // Toast import 'package:fluttertoast/fluttertoast.dart'; // Toast
//
import '../../config/config.dart';
class MainPage extends StatefulWidget { class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key); const MainPage({Key? key}) : super(key: key);
@ -30,6 +33,7 @@ class _MainPageState extends State<MainPage> {
/// (1) /// (1)
BannerAd? _bannerAd; BannerAd? _bannerAd;
bool _isBannerReady = false; // bool _isBannerReady = false; //
String adUnitId = Config.testAdUnitId;
// //
DateTime? _lastPressedTime; DateTime? _lastPressedTime;
@ -53,12 +57,18 @@ class _MainPageState extends State<MainPage> {
_initBannerAd(); _initBannerAd();
} }
@override
void dispose() {
_bannerAd?.dispose();
super.dispose();
}
/// ///
void _initBannerAd() { void _initBannerAd() {
_bannerAd = BannerAd( _bannerAd = BannerAd(
size: AdSize.banner, // size: AdSize.banner, //
// adUnitId: 'ca-app-pub-3940256099942544/6300978111' () // adUnitId: 'ca-app-pub-3940256099942544/6300978111' ()
adUnitId: 'ca-app-pub-3940256099942544/6300978111', // : ID adUnitId: adUnitId, // / ID
listener: BannerAdListener( listener: BannerAdListener(
onAdLoaded: (Ad ad) { onAdLoaded: (Ad ad) {
setState(() => _isBannerReady = true); setState(() => _isBannerReady = true);
@ -76,12 +86,6 @@ class _MainPageState extends State<MainPage> {
_bannerAd?.load(); _bannerAd?.load();
} }
@override
void dispose() {
_bannerAd?.dispose(); //
super.dispose();
}
Future<bool> _onWillPop() async { Future<bool> _onWillPop() async {
final now = DateTime.now(); final now = DateTime.now();
if (_lastPressedTime == null || if (_lastPressedTime == null ||
@ -243,26 +247,6 @@ class _MainPageState extends State<MainPage> {
style: TextStyle(color: Colors.black), style: TextStyle(color: Colors.black),
), ),
), ),
//
Center(
child: OutlinedButton(
onPressed: () {
// TODO
},
style: OutlinedButton.styleFrom(
backgroundColor: Colors.white,
side: const BorderSide(color: Colors.black54, width: 1),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 60),
),
child: const Text(
'방 생성 완료 이동(임시)',
style: TextStyle(color: Colors.black, fontSize: 16),
),
),
),
const SizedBox(height: 16),
], ],
), ),
), ),

View File

@ -3,8 +3,13 @@ import 'dart:async';
import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_database/firebase_database.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
//
import 'main_page.dart'; import 'main_page.dart';
// API
import '../../plugins/api.dart'; import '../../plugins/api.dart';
//
import '../../dialogs/response_dialog.dart'; import '../../dialogs/response_dialog.dart';
import '../../dialogs/yes_no_dialog.dart'; import '../../dialogs/yes_no_dialog.dart';
import '../../dialogs/room_setting_dialog.dart'; import '../../dialogs/room_setting_dialog.dart';
@ -12,6 +17,12 @@ import '../../dialogs/user_info_team_dialog.dart';
import '../../dialogs/team_name_edit_dialog.dart'; import '../../dialogs/team_name_edit_dialog.dart';
import 'playing_team_page.dart'; import 'playing_team_page.dart';
//
import 'package:google_mobile_ads/google_mobile_ads.dart';
//
import '../../config/config.dart';
class WaitingRoomTeamPage extends StatefulWidget { class WaitingRoomTeamPage extends StatefulWidget {
final int roomSeq; final int roomSeq;
final String roomType; // "team" final String roomType; // "team"
@ -43,12 +54,17 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
bool _isLoading = true; bool _isLoading = true;
//
bool _isServerRequestLoading = false;
late DatabaseReference _roomRef; late DatabaseReference _roomRef;
Stream<DatabaseEvent>? _roomStream; Stream<DatabaseEvent>? _roomStream;
StreamSubscription<DatabaseEvent>? _roomStreamSubscription; StreamSubscription<DatabaseEvent>? _roomStreamSubscription;
bool _movedToRunningPage = false; bool _movedToRunningPage = false;
bool _kickedOut = false; bool _kickedOut = false;
bool _roomTimeOut = false;
String _roomTimeOutMsg = '';
String mySeq = '0'; String mySeq = '0';
@ -57,10 +73,21 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
Duration _remaining = const Duration(hours: 1); Duration _remaining = const Duration(hours: 1);
DateTime? _createDt; DateTime? _createDt;
/// (1)
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.testAdUnitId;
// SEQ
String _masterSeqString = '';
@override @override
void initState() { void initState() {
super.initState(); super.initState();
FirebaseDatabase.instance.goOnline(); FirebaseDatabase.instance.goOnline();
// (C)
_initBannerAd();
// (D)
_initRoomRef(); _initRoomRef();
} }
@ -86,6 +113,29 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
super.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 _listenRoomData() { void _listenRoomData() {
_roomStream = _roomRef.onValue; _roomStream = _roomRef.onValue;
_roomStreamSubscription = _roomStream?.listen((event) { _roomStreamSubscription = _roomStream?.listen((event) {
@ -101,7 +151,28 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
final data = snapshot.value as Map<dynamic, dynamic>? ?? {}; final data = snapshot.value as Map<dynamic, dynamic>? ?? {};
final roomInfoData = data['roomInfo'] as Map<dynamic, dynamic>? ?? {}; final roomInfoData = data['roomInfo'] as Map<dynamic, dynamic>? ?? {};
final userInfoData = data['userInfo'] as Map<dynamic, dynamic>? ?? {}; // final userInfoData = data['userInfo'] as Map<dynamic, dynamic>? ?? {};
final userInfoDynamic = data['userInfo']; // List일
final tempList = <Map<String, dynamic>>[];
// userList
if (userInfoDynamic is Map) {
userInfoDynamic.forEach((key, val) {
if (val is Map) {
tempList.add({
'user_seq': val['user_seq'].toString() ?? '0',
'participant_type': val['participant_type'] ?? '',
'nickname': val['nickname'] ?? '유저',
'team_name': val['team_name'] ?? '',
'score': val['score'] ?? 0,
'profile_img': val['profile_img'] ?? '',
'introduce_myself': val['introduce_myself'] ?? '',
'ready_yn': (val['ready_yn'] ?? 'N').toString().toUpperCase(),
'connect_yn': (val['connect_yn'] ?? 'Y').toString().toUpperCase(),
});
}
});
}
final roomStatus = (roomInfoData['room_status'] ?? 'WAIT').toString().toUpperCase(); final roomStatus = (roomInfoData['room_status'] ?? 'WAIT').toString().toUpperCase();
@ -130,21 +201,12 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
roomMasterYn = 'Y'; roomMasterYn = 'Y';
} }
// userList if (masterSeq != null) {
final tempList = <Map<String, dynamic>>[]; _masterSeqString = masterSeq.toString();
userInfoData.forEach((userSeq, userMap) { } else {
tempList.add({ _masterSeqString = '';
'user_seq': userSeq, }
'participant_type': userMap['participant_type'] ?? '',
'nickname': userMap['nickname'] ?? '유저',
'team_name': userMap['team_name'] ?? '',
'score': userMap['score'] ?? 0,
'profile_img': userMap['profile_img'] ?? '',
'introduce_myself': userMap['introduce_myself'] ?? '',
'ready_yn': (userMap['ready_yn'] ?? 'N').toString().toUpperCase(),
'connect_yn': (userMap['connect_yn'] ?? 'Y').toString().toUpperCase(),
});
});
_userList = tempList; _userList = tempList;
_isLoading = false; _isLoading = false;
}); });
@ -152,7 +214,7 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
// -> // ->
if (roomStatus == 'RUNNING' && !_movedToRunningPage) { if (roomStatus == 'RUNNING' && !_movedToRunningPage) {
_movedToRunningPage = true; _movedToRunningPage = true;
Navigator.pushReplacement( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => PlayingTeamPage( builder: (_) => PlayingTeamPage(
@ -160,16 +222,28 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
roomTitle: roomTitle, roomTitle: roomTitle,
), ),
), ),
(route) => false,
); );
return; return;
} }
// (C) create_dt -> 1 // (C) create_dt -> 1
final createDtStr = (roomInfoData['create_dt'] ?? '') as String; final createDtStr = (roomInfoData['create_dt'] ?? '') as String;
if (createDtStr.isNotEmpty && createDtStr.contains('T')) { if (createDtStr.isNotEmpty) {
final dt = DateTime.tryParse(createDtStr); final dotIndex = createDtStr.indexOf('.');
final isoStr = createDtStr.substring(0, dotIndex);
print('isoStr: $isoStr');
final dt1 = DateTime.tryParse(createDtStr);
print('dt1: $dt1');
final dt = DateTime.tryParse(isoStr);
print('dt: $dt');
final dt2 = DateTime.parse(isoStr);
print('dt2: $dt2');
if (dt != null) { if (dt != null) {
setState(() {
_createDt = dt; _createDt = dt;
});
_startCountdownTimer(); _startCountdownTimer();
} }
} }
@ -178,11 +252,17 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
final amIStillHere = _userList.any((u) => u['user_seq'].toString() == mySeq); final amIStillHere = _userList.any((u) => u['user_seq'].toString() == mySeq);
if (!amIStillHere && !_kickedOut && roomMasterYn != 'Y') { if (!amIStillHere && !_kickedOut && roomMasterYn != 'Y') {
_kickedOut = true; _kickedOut = true;
if (_roomTimeOut) {
_roomTimeOutMsg = '방장이 나갔습니다.';
} else if (_kickedOut) {
_roomTimeOutMsg = '강퇴되었습니다.';
}
Future.delayed(Duration.zero, () async { Future.delayed(Duration.zero, () async {
await showResponseDialog(context, '안내', '강퇴되었습니다.'); await showResponseDialog(context, '안내', _roomTimeOutMsg);
Navigator.pushReplacement( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute(builder: (_) => const MainPage()), MaterialPageRoute(builder: (_) => const MainPage()),
(route) => false,
); );
}); });
} }
@ -202,7 +282,8 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
if (_createDt == null) return; if (_createDt == null) return;
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) { _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
final endTime = _createDt!.add(const Duration(hours: 1)); // final endTime = _createDt!.add(const Duration(hours: 1));
final endTime = _createDt!.add(const Duration(minutes: 1));
final now = DateTime.now(); final now = DateTime.now();
final diff = endTime.difference(now); final diff = endTime.difference(now);
@ -220,6 +301,9 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
void _onAutoTimeout() { void _onAutoTimeout() {
// -> =(), = // -> =(), =
setState(() {
_roomTimeOut = true;
});
_requestLeaveRoom(); _requestLeaveRoom();
} }
@ -232,7 +316,11 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
// ... // ...
} }
if (mounted) { if (mounted) {
Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => const MainPage())); Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => const MainPage()),
(route) => false,
);
} }
} }
@ -302,7 +390,7 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
Widget _buildTopButtons() { Widget _buildTopButtons() {
if (_isLoading) return const SizedBox(); 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 myReadyYn = (me['ready_yn'] ?? 'N').toString().toUpperCase();
final bool isReady = (myReadyYn == 'Y'); final bool isReady = (myReadyYn == 'Y');
final readyLabel = isReady ? '준비완료' : '준비'; final readyLabel = isReady ? '준비완료' : '준비';
@ -341,8 +429,10 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
margin: const EdgeInsets.symmetric(horizontal: 4), margin: const EdgeInsets.symmetric(horizontal: 4),
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _onGameStart, onPressed: _isServerRequestLoading ? null : _onGameStart,
child: const Text('게임 시작'), child: _isServerRequestLoading
? const CircularProgressIndicator()
: const Text('게임 시작'),
), ),
), ),
), ),
@ -378,7 +468,7 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
Future<void> _onToggleReady() async { Future<void> _onToggleReady() async {
try { try {
final me = _userList.firstWhere((u) => (u['user_seq'] ?? '') == mySeq, orElse: () => {}); final me = _userList.firstWhere((u) => (u['user_seq'].toString() ?? '') == mySeq, orElse: () => {});
final myReadyYn = (me['ready_yn'] ?? 'N').toString().toUpperCase(); final myReadyYn = (me['ready_yn'] ?? 'N').toString().toUpperCase();
final isReady = (myReadyYn == 'Y'); final isReady = (myReadyYn == 'Y');
final newYn = isReady ? 'N' : 'Y'; final newYn = isReady ? 'N' : 'Y';
@ -386,7 +476,7 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
final userRef = _roomRef.child('userInfo').child(mySeq); final userRef = _roomRef.child('userInfo').child(mySeq);
await userRef.update({"ready_yn": newYn}); await userRef.update({"ready_yn": newYn});
} catch (e) { } catch (e) {
print('READY 설정 실패: $e'); showResponseDialog(context, '오류', 'READY 설정에 실패했습니다.');
} }
} }
@ -417,9 +507,11 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
} }
Future<void> _onGameStart() async { Future<void> _onGameStart() async {
setState(() => _isServerRequestLoading = true);
final notReady = _userList.any((u) => (u['ready_yn'] ?? 'N').toString().toUpperCase() != 'Y'); final notReady = _userList.any((u) => (u['ready_yn'] ?? 'N').toString().toUpperCase() != 'Y');
if (notReady) { if (notReady) {
showResponseDialog(context, '안내', 'READY되지 않은 참가자가 있습니다(방장 포함).'); showResponseDialog(context, '안내', '아직 준비되지 않은 참가자가 있습니다(방장 포함).');
setState(() => _isServerRequestLoading = false);
return; return;
} }
@ -434,13 +526,18 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
if (resp['result'] == 'OK') { if (resp['result'] == 'OK') {
print('게임 시작 요청 성공(팀전)'); print('게임 시작 요청 성공(팀전)');
} else { } else {
// ... //
showResponseDialog(context, '오류', '게임 시작 요청에 실패했습니다.');
} }
} else { } else {
// ... //
showResponseDialog(context, '오류', '게임 시작 요청에 실패했습니다.');
} }
} catch (e) { } catch (e) {
// ... //
showResponseDialog(context, '오류', '게임 시작 요청에 실패했습니다.');
} finally {
setState(() => _isServerRequestLoading = false);
} }
} }
@ -461,25 +558,34 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
backgroundColor: Colors.black, backgroundColor: Colors.black,
elevation: 0, elevation: 0,
// + // +
title: Text( title: Row(
(roomTitle.isNotEmpty ? roomTitle : '방 제목') + ' [$countdownStr]', mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// :
Text(
roomTitle.isNotEmpty ? roomTitle : '방 제목',
style: const TextStyle(color: Colors.white), style: const TextStyle(color: Colors.white),
), ),
// :
Text(
countdownStr, // : "10:23"
style: const TextStyle(color: Colors.white),
),
],
),
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.white), icon: const Icon(Icons.arrow_back_ios, color: Colors.white),
onPressed: _onLeaveRoom, onPressed: _onLeaveRoom,
), ),
), ),
bottomNavigationBar: Container( bottomNavigationBar: _isBannerReady && _bannerAd != null
height: 50, ? Container(
decoration: BoxDecoration( color: Colors.white,
color: Colors.grey.shade300, width: _bannerAd!.size.width.toDouble(),
border: Border.all(color: Colors.black, width: 1), height: _bannerAd!.size.height.toDouble(),
), child: AdWidget(ad: _bannerAd!),
child: const Center( )
child: Text('구글 광고', style: TextStyle(color: Colors.black)), : SizedBox.shrink(), // or
),
),
body: _isLoading body: _isLoading
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: SingleChildScrollView( : SingleChildScrollView(
@ -490,10 +596,10 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
_buildTopButtons(), _buildTopButtons(),
const SizedBox(height: 20), const SizedBox(height: 20),
const Text('사회자', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black)), // const Text('사회자', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black)),
const SizedBox(height: 8), // const SizedBox(height: 8),
_buildAdminSection(), // _buildAdminSection(),
const SizedBox(height: 20), // const SizedBox(height: 20),
const Text('팀별 참가자', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black)), const Text('팀별 참가자', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black)),
const SizedBox(height: 8), const SizedBox(height: 8),
@ -507,34 +613,35 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
); );
} }
Widget _buildAdminSection() { // Widget _buildAdminSection() {
final adminList = _userList.where((u) { // final adminList = _userList.where((u) {
final pType = (u['participant_type'] ?? '').toString().toUpperCase(); // final pType = (u['participant_type'] ?? '').toString().toUpperCase();
return pType == 'ADMIN'; // return pType == 'ADMIN';
}).toList(); // }).toList();
return Container( // return Container(
padding: const EdgeInsets.all(8), // padding: const EdgeInsets.all(8),
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Colors.white, // color: Colors.white,
border: Border.all(color: Colors.black), // border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(8), // borderRadius: BorderRadius.circular(8),
), // ),
child: adminList.isEmpty // child: adminList.isEmpty
? const Text('사회자가 없습니다.', style: TextStyle(color: Colors.black)) // ? const Text('사회자가 없습니다.', style: TextStyle(color: Colors.black))
: Wrap( // : Wrap(
spacing: 16, // spacing: 16,
runSpacing: 8, // runSpacing: 8,
children: adminList.map(_buildSeat).toList(), // children: adminList.map(_buildSeat).toList(),
), // ),
); // );
} // }
Widget _buildTeamSection() { Widget _buildTeamSection() {
final players = _userList.where((u) { // final players = _userList.where((u) {
final pType = (u['participant_type'] ?? '').toString().toUpperCase(); // final pType = (u['participant_type'] ?? '').toString().toUpperCase();
return (pType != 'ADMIN'); // return (pType != 'ADMIN');
}).toList(); // }).toList();
final players = _userList.toList();
final Map<String, List<Map<String, dynamic>>> teamMap = {}; final Map<String, List<Map<String, dynamic>>> teamMap = {};
for (final tName in _teamNameList) { for (final tName in _teamNameList) {
@ -619,7 +726,7 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
Widget _buildWaitSection() { Widget _buildWaitSection() {
final waitList = _userList.where((u) { final waitList = _userList.where((u) {
final pType = (u['participant_type'] ?? '').toString().toUpperCase(); final pType = (u['participant_type'] ?? '').toString().toUpperCase();
if (pType == 'ADMIN') return false; // if (pType == 'ADMIN') return false;
final tName = (u['team_name'] ?? '').toString().toUpperCase(); final tName = (u['team_name'] ?? '').toString().toUpperCase();
return (tName.isEmpty || tName == 'WAIT'); return (tName.isEmpty || tName == 'WAIT');
}).toList(); }).toList();
@ -662,6 +769,24 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
final bool isDisconnected = (connectYn == 'N'); final bool isDisconnected = (connectYn == 'N');
final bool isMaster = (roomMasterYn == 'Y'); final bool isMaster = (roomMasterYn == 'Y');
// user가
final isRoomMasterUser = (user['user_seq']?.toString() ?? '') == _masterSeqString;
// user가
final participantType = (user['participant_type'] ?? '').toString().toUpperCase();
final isAdmin = (participantType == 'ADMIN');
//
String roleIcon = '';
if (isRoomMasterUser) {
//
roleIcon = '';
} else if (isAdmin) {
//
roleIcon = '';
}
final displayName = '$roleIcon$userName';
return GestureDetector( return GestureDetector(
onTap: () async { onTap: () async {
final result = await showDialog( final result = await showDialog(
@ -738,7 +863,7 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
), ),
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
Text(userName, style: const TextStyle(fontSize: 12, color: Colors.black)), Text(displayName, style: const TextStyle(fontSize: 12, color: Colors.black)),
], ],
), ),
), ),