1차 최종

This commit is contained in:
eld_master 2025-01-22 19:51:36 +09:00
parent b34802b894
commit 7278c6e06e
24 changed files with 1143 additions and 1060 deletions

View File

@ -20,8 +20,8 @@ android {
applicationId "com.allscore_app" applicationId "com.allscore_app"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 34 targetSdkVersion 34
versionCode 1 versionCode 4
versionName "1.0" versionName "1.0.3"
} }
// ... // ...

View File

@ -5,6 +5,7 @@ class Config {
static const String realAdUnitId = 'ca-app-pub-6461991944599918~9492697896'; static const String realAdUnitId = 'ca-app-pub-6461991944599918~9492697896';
// ID // ID
static const String adUnitId = 'ca-app-pub-6461991944599918~9492697896'; static const String adUnitId = 'ca-app-pub-6461991944599918~9492697896';
// static const String adUnitId = 'ca-app-pub-3940256099942544/6300978111';
// //
static const String baseUrl = 'https://eldsoft.com:8097'; static const String baseUrl = 'https://eldsoft.com:8097';
// //

View File

@ -64,8 +64,9 @@ class _ScoreEditDialogState extends State<ScoreEditDialog> {
void _onDelta(int delta) { void _onDelta(int delta) {
setState(() { setState(() {
newScore += delta; newScore += delta;
if (newScore < 0) newScore = 0; // 0 // if (newScore < 0) newScore = 0; // 0
if (newScore > 999999) newScore = 999999; // if (newScore > 999999) newScore = 999999; //
if (newScore < -999999) newScore = -999999; //
}); });
} }
@ -122,18 +123,25 @@ class _ScoreEditDialogState extends State<ScoreEditDialog> {
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Wrap( SizedBox(
spacing: 4, // height: 120, //
runSpacing: 4, child: GridView.count(
crossAxisCount: 2, // 3
mainAxisSpacing: 8,
crossAxisSpacing: 8,
childAspectRatio: 2.0, // :
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: [ children: [
_buildDeltaButton(-100), _buildDeltaButton(-100),
_buildDeltaButton(100),
_buildDeltaButton(-10), _buildDeltaButton(-10),
_buildDeltaButton(10),
_buildDeltaButton(-1), _buildDeltaButton(-1),
_buildDeltaButton(1), _buildDeltaButton(1),
_buildDeltaButton(10),
_buildDeltaButton(100),
], ],
), ),
),
const SizedBox(height: 12), const SizedBox(height: 12),
Row( Row(

View File

@ -121,7 +121,7 @@ class _TeamNameEditModalState extends State<TeamNameEditModal> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
SizedBox( SizedBox(
width: 100, width: 80,
child: ElevatedButton( child: ElevatedButton(
onPressed: _onUpdateTeamName, onPressed: _onUpdateTeamName,
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
@ -130,7 +130,7 @@ class _TeamNameEditModalState extends State<TeamNameEditModal> {
), ),
), ),
SizedBox( SizedBox(
width: 100, width: 80,
child: ElevatedButton( child: ElevatedButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),

View File

@ -23,7 +23,7 @@ class UserInfoBasicDialog extends StatelessWidget {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Text('유저 정보 (진행중-개인전)', const Text('유저 정보',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 12), const SizedBox(height: 12),

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'response_dialog.dart'; import 'response_dialog.dart';
import '../../plugins/api.dart'; import '../../plugins/api.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:auto_size_text/auto_size_text.dart';
class UserInfoPrivateDialog extends StatefulWidget { class UserInfoPrivateDialog extends StatefulWidget {
final Map<String, dynamic> userData; final Map<String, dynamic> userData;
@ -24,6 +26,10 @@ class _UserInfoPrivateDialogState extends State<UserInfoPrivateDialog> {
late String participantType; // 'ADMIN' or 'PLAYER' late String participantType; // 'ADMIN' or 'PLAYER'
late String introduceMyself; late String introduceMyself;
//
double scaleFactor = 1.0;
double buttonScaleFactor = 1.0;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -32,6 +38,22 @@ class _UserInfoPrivateDialogState extends State<UserInfoPrivateDialog> {
introduceMyself = widget.userData['introduce_myself'] ?? ''; introduceMyself = widget.userData['introduce_myself'] ?? '';
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_updateScaleFactor();
}
//
void _updateScaleFactor() {
final screenWidth = MediaQuery.of(context).size.width;
const baseWidth = 450.0;
setState(() {
scaleFactor = (screenWidth / baseWidth).clamp(0.8, 1.2);
buttonScaleFactor = (screenWidth / baseWidth).clamp(0.6, 1.2);
});
}
/// API ( ) /// API ( )
Future<void> _onUpdateUserInfo() async { Future<void> _onUpdateUserInfo() async {
// //
@ -71,6 +93,13 @@ class _UserInfoPrivateDialogState extends State<UserInfoPrivateDialog> {
Future<void> _onKickParticipant() async { Future<void> _onKickParticipant() async {
// -> return // -> return
if (!widget.isRoomMaster) return; if (!widget.isRoomMaster) return;
//
final prefs = await SharedPreferences.getInstance();
final mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0';
if (widget.userData['user_seq'] == mySeq) {
await showResponseDialog(context, '오류', '방장은 추방할 수 없습니다.');
return;
}
final reqBody = { final reqBody = {
"room_seq": "${widget.roomSeq}", "room_seq": "${widget.roomSeq}",
@ -116,7 +145,7 @@ class _UserInfoPrivateDialogState extends State<UserInfoPrivateDialog> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Text( const Text(
'유저 정보 (개인전)', '유저 정보',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
@ -224,34 +253,40 @@ class _UserInfoPrivateDialogState extends State<UserInfoPrivateDialog> {
children: [ children: [
// (D-1) // (D-1)
SizedBox( SizedBox(
width: 90, width: scaleFactor==0.8 ? 50 : 90,
child: ElevatedButton( child: ElevatedButton(
onPressed: _onUpdateUserInfo, onPressed: _onUpdateUserInfo,
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
child: FittedBox( child: AutoSizeText(
child: Text('수정하기', style: TextStyle(color: Colors.white)), scaleFactor==0.8 ? '수정' : '수정하기',
maxLines: 1,
style: TextStyle(color: Colors.white),
), ),
), ),
), ),
// (D-2) // (D-2)
SizedBox( SizedBox(
width: 90, width: scaleFactor==0.8 ? 50 : 90,
child: ElevatedButton( child: ElevatedButton(
onPressed: _onKickParticipant, onPressed: _onKickParticipant,
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
child: FittedBox( child: AutoSizeText(
child: Text('추방하기', style: TextStyle(color: Colors.white)), scaleFactor==0.8 ? '추방' : '추방하기',
maxLines: 1,
style: TextStyle(color: Colors.white),
), ),
), ),
), ),
// (D-3) // (D-3)
SizedBox( SizedBox(
width: 90, width: scaleFactor==0.8 ? 50 : 90,
child: ElevatedButton( child: ElevatedButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
child: FittedBox( child: AutoSizeText(
child: Text('확인', style: TextStyle(color: Colors.white)), '확인',
maxLines: 1,
style: TextStyle(color: Colors.white),
), ),
), ),
), ),
@ -261,7 +296,11 @@ class _UserInfoPrivateDialogState extends State<UserInfoPrivateDialog> {
ElevatedButton( ElevatedButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
child: const Text('확인', style: TextStyle(color: Colors.white)), child: AutoSizeText(
'확인',
maxLines: 1,
style: TextStyle(color: Colors.white),
),
), ),
], ],
], ],

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'response_dialog.dart'; import 'response_dialog.dart';
import '../../plugins/api.dart'; import '../../plugins/api.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:auto_size_text/auto_size_text.dart';
class UserInfoTeamDialog extends StatefulWidget { class UserInfoTeamDialog extends StatefulWidget {
final Map<String, dynamic> userData; final Map<String, dynamic> userData;
@ -27,6 +29,10 @@ class _UserInfoTeamDialogState extends State<UserInfoTeamDialog> {
late String teamName; // 'A'/'B'/'WAIT' late String teamName; // 'A'/'B'/'WAIT'
late String introduceMyself; // late String introduceMyself; //
//
double scaleFactor = 1.0;
double buttonScaleFactor = 1.0;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -45,6 +51,22 @@ class _UserInfoTeamDialogState extends State<UserInfoTeamDialog> {
} }
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_updateScaleFactor();
}
//
void _updateScaleFactor() {
final screenWidth = MediaQuery.of(context).size.width;
const baseWidth = 450.0;
setState(() {
scaleFactor = (screenWidth / baseWidth).clamp(0.8, 1.2);
buttonScaleFactor = (screenWidth / baseWidth).clamp(0.6, 1.2);
});
}
// (1) / API ( ) // (1) / API ( )
Future<void> _onUpdateUserInfo() async { Future<void> _onUpdateUserInfo() async {
// -> return // -> return
@ -85,6 +107,13 @@ class _UserInfoTeamDialogState extends State<UserInfoTeamDialog> {
Future<void> _onKickParticipant() async { Future<void> _onKickParticipant() async {
// //
if (!widget.isRoomMaster) return; if (!widget.isRoomMaster) return;
//
final prefs = await SharedPreferences.getInstance();
final mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0';
if (widget.userData['user_seq'] == mySeq) {
await showResponseDialog(context, '오류', '방장은 추방할 수 없습니다.');
return;
}
final reqBody = { final reqBody = {
"room_seq": "${widget.roomSeq}", "room_seq": "${widget.roomSeq}",
@ -124,12 +153,13 @@ class _UserInfoTeamDialogState extends State<UserInfoTeamDialog> {
return Dialog( return Dialog(
backgroundColor: Colors.white, backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
insetPadding: const EdgeInsets.symmetric(horizontal: 20),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Text('유저 정보 (팀전)', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), const Text('유저 정보', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 12), const SizedBox(height: 12),
// (A) // (A)
@ -257,47 +287,44 @@ class _UserInfoTeamDialogState extends State<UserInfoTeamDialog> {
children: [ children: [
// //
SizedBox( SizedBox(
width: 90, width: scaleFactor==0.8 ? 75 : 90,
child: ElevatedButton( child: ElevatedButton(
onPressed: _onUpdateUserInfo, onPressed: _onUpdateUserInfo,
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
// () FittedBox // () FittedBox
child: FittedBox( child: AutoSizeText(
child: Text( scaleFactor==0.8 ? '수정' : '수정하기',
'수정하기', maxLines: 1,
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
), ),
), ),
), ),
),
// //
SizedBox( SizedBox(
width: 90, width: scaleFactor==0.8 ? 75 : 90,
child: ElevatedButton( child: ElevatedButton(
onPressed: _onKickParticipant, onPressed: _onKickParticipant,
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
child: FittedBox( child: AutoSizeText(
child: Text( scaleFactor==0.8 ? '추방' : '추방하기',
'추방하기', maxLines: 1,
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
), ),
), ),
), ),
),
// //
SizedBox( SizedBox(
width: 90, width: scaleFactor==0.8 ? 75 : 90,
child: ElevatedButton( child: ElevatedButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
child: FittedBox( child: AutoSizeText(
child: Text(
'확인', '확인',
maxLines: 1,
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
), ),
), ),
), ),
),
], ],
), ),
] else ...[ ] else ...[
@ -305,7 +332,11 @@ class _UserInfoTeamDialogState extends State<UserInfoTeamDialog> {
ElevatedButton( ElevatedButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(backgroundColor: Colors.black), style: ElevatedButton.styleFrom(backgroundColor: Colors.black),
child: const Text('확인', style: TextStyle(color: Colors.white)), child: AutoSizeText(
'확인',
maxLines: 1,
style: TextStyle(color: Colors.white),
),
), ),
], ],
], ],

85
lib/plugins/admob.dart Normal file
View File

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
// import 'package:google_mobile_ads/google_mobile_ads.dart';
// import '../config/config.dart';
/*
// ================== ( ) ==================
// class AdBannerWidget extends StatefulWidget {
// const AdBannerWidget({Key? key}) : super(key: key);
// @override
// State<AdBannerWidget> createState() => _AdBannerWidgetState();
// }
// class _AdBannerWidgetState extends State<AdBannerWidget> {
// BannerAd? _bannerAd; //
// @override
// void initState() {
// super.initState();
// _initBannerAd();
// }
// @override
// void dispose() {
// _bannerAd?.dispose();
// super.dispose();
// }
// /// &
// void _initBannerAd() {
// _bannerAd = BannerAd(
// size: AdSize.banner, // ()
// adUnitId: Config.adUnitId, // ID (Config에서 )
// listener: BannerAdListener(
// onAdLoaded: (Ad ad) {
// // : _bannerAd를 .
// setState(() {/* 굳이 아무 것도 안 해도 됨 */});
// },
// onAdFailedToLoad: (Ad ad, LoadAdError error) {
// // : & null
// ad.dispose();
// setState(() {
// _bannerAd = null;
// });
// },
// ),
// request: const AdRequest(),
// );
// //
// _bannerAd!.load();
// }
// @override
// Widget build(BuildContext context) {
// // / _bannerAd가 null
// if (_bannerAd == null) {
// return const SizedBox.shrink();
// }
// // Container에 AdWidget으로
// return Container(
// color: Colors.white, //
// width: _bannerAd!.size.width.toDouble(),
// height: _bannerAd!.size.height.toDouble(),
// child: AdWidget(ad: _bannerAd!),
// );
// }
// }
*/
// ================== / ==================
class AdBannerWidget extends StatelessWidget {
const AdBannerWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// () 50dp
// or return SizedBox.shrink()
return const SizedBox(
height: 50, //
child: ColoredBox(color: Colors.white), //
);
}
}

View File

@ -130,7 +130,7 @@ class _SurveyPageState extends State<SurveyPage> {
} }
final requestBody = { final requestBody = {
"QNA": qnaList.toString(), "QNA": qnaList,
}; };
try { try {

View File

@ -7,7 +7,7 @@ import 'pw_finding_page.dart';
import 'signup_page.dart'; import 'signup_page.dart';
// //
import 'package:google_mobile_ads/google_mobile_ads.dart'; import '../../plugins/admob.dart';
// //
import '../../config/config.dart'; import '../../config/config.dart';
@ -27,11 +27,6 @@ class _IdFindingPageState extends State<IdFindingPage> {
String foundIdMessage = ''; String foundIdMessage = '';
String authId = ''; String authId = '';
/// (1)
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.adUnitId;
Future<void> _findId(String nickname, String email) async { Future<void> _findId(String nickname, String email) async {
@ -100,30 +95,10 @@ class _IdFindingPageState extends State<IdFindingPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initBannerAd();
}
void _initBannerAd() {
_bannerAd = BannerAd(
// / ID
adUnitId: adUnitId,
size: AdSize.banner,
request: const AdRequest(),
listener: BannerAdListener(
onAdLoaded: (ad) {
setState(() => _isBannerReady = true);
},
onAdFailedToLoad: (ad, error) {
ad.dispose();
},
),
);
_bannerAd?.load();
} }
@override @override
void dispose() { void dispose() {
_bannerAd?.dispose();
super.dispose(); super.dispose();
} }
@ -349,14 +324,7 @@ class _IdFindingPageState extends State<IdFindingPage> {
), ),
// (3) // (3)
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
); );
} }
} }

View File

@ -369,7 +369,7 @@ class _LoginPageState extends State<LoginPage> {
. .
7. 7.
: eld_yeojh@naver.com : eldyeojh@gmail.com
8. 8.
, . , .

View File

@ -7,7 +7,7 @@ import 'signup_page.dart'; // 회원가입 페이지 임포트 추가
import 'id_finding_page.dart'; // ID import 'id_finding_page.dart'; // ID
// //
import 'package:google_mobile_ads/google_mobile_ads.dart'; import '../../plugins/admob.dart';
// //
import '../../config/config.dart'; import '../../config/config.dart';
@ -25,11 +25,6 @@ class _PwFindingPageState extends State<PwFindingPage> {
String emailErrorMessage = ''; // String emailErrorMessage = ''; //
String idErrorMessage = ''; // ID String idErrorMessage = ''; // ID
/// (1)
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.adUnitId;
Future<void> _findPassword(String id, String email) async { Future<void> _findPassword(String id, String email) async {
// PW // PW
@ -125,30 +120,10 @@ class _PwFindingPageState extends State<PwFindingPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initBannerAd();
}
void _initBannerAd() {
_bannerAd = BannerAd(
// / ID
adUnitId: adUnitId,
size: AdSize.banner,
request: const AdRequest(),
listener: BannerAdListener(
onAdLoaded: (ad) {
setState(() => _isBannerReady = true);
},
onAdFailedToLoad: (ad, error) {
ad.dispose();
},
),
);
_bannerAd?.load();
} }
@override @override
void dispose() { void dispose() {
_bannerAd?.dispose();
super.dispose(); super.dispose();
} }
@ -254,14 +229,7 @@ class _PwFindingPageState extends State<PwFindingPage> {
), ),
// (3) // (3)
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
); );
} }
} }

View File

@ -253,8 +253,7 @@ class _SignUpPageState extends State<SignUpPage> {
'이용자는 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다.\n' '이용자는 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다.\n'
'그러나 필수 항목에 대한 동의를 거부하실 경우 서비스 이용이 제한될 수 있습니다.\n\n' '그러나 필수 항목에 대한 동의를 거부하실 경우 서비스 이용이 제한될 수 있습니다.\n\n'
'7. 개인정보 보호책임자\n' '7. 개인정보 보호책임자\n'
'이름: 여정훈\n' '연락처: eldyeojh@gmail.com\n\n'
'연락처: eld_yeojh@naver.com\n\n'
'8. 개인정보의 안전성 확보 조치\n' '8. 개인정보의 안전성 확보 조치\n'
'회사는 개인정보의 안전한 처리를 위하여 기술적, 관리적 보호조치를 시행하고 있습니다.\n' '회사는 개인정보의 안전한 처리를 위하여 기술적, 관리적 보호조치를 시행하고 있습니다.\n'
'개인정보의 암호화\n' '개인정보의 암호화\n'

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
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 'package:google_mobile_ads/google_mobile_ads.dart'; // AdMob
// import... // import...
import '../../dialogs/settings_dialog.dart'; import '../../dialogs/settings_dialog.dart';
@ -25,6 +24,9 @@ import '../../config/config.dart';
// //
import '../../dialogs/survey_dialog.dart'; import '../../dialogs/survey_dialog.dart';
//
import '../../plugins/admob.dart';
class MainPage extends StatefulWidget { class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key); const MainPage({Key? key}) : super(key: key);
@ -33,11 +35,6 @@ class MainPage extends StatefulWidget {
} }
class _MainPageState extends State<MainPage> { class _MainPageState extends State<MainPage> {
/// (1)
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.adUnitId;
// //
DateTime? _lastPressedTime; DateTime? _lastPressedTime;
@ -55,38 +52,13 @@ class _MainPageState extends State<MainPage> {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_checkLandingMainPageInfo(); _checkLandingMainPageInfo();
}); });
// (C)
_initBannerAd();
} }
@override @override
void dispose() { void dispose() {
_bannerAd?.dispose();
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);
},
onAdFailedToLoad: (Ad ad, LoadAdError err) {
ad.dispose();
},
),
request: const AdRequest(),
);
// load()
_bannerAd?.load();
}
Future<bool> _onWillPop() async { Future<bool> _onWillPop() async {
final now = DateTime.now(); final now = DateTime.now();
if (_lastPressedTime == null || if (_lastPressedTime == null ||
@ -202,14 +174,7 @@ class _MainPageState extends State<MainPage> {
], ],
), ),
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
body: Column( body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,

View File

@ -9,8 +9,8 @@ import '../../plugins/api.dart';
import '../../dialogs/response_dialog.dart'; import '../../dialogs/response_dialog.dart';
import '../../dialogs/score_edit_dialog.dart'; // import '../../dialogs/score_edit_dialog.dart'; //
import '../../dialogs/user_info_basic_dialog.dart'; // import '../../dialogs/user_info_basic_dialog.dart'; //
import '../../plugins/admob.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../../config/config.dart'; import '../../config/config.dart';
class PlayingPrivatePage extends StatefulWidget { class PlayingPrivatePage extends StatefulWidget {
@ -58,14 +58,12 @@ class _PlayingPrivatePageState extends State<PlayingPrivatePage> {
String mySeq = '0'; String mySeq = '0';
//
String myParticipantType = 'PLAYER';
// userListMap: { userSeq: true/false } // userListMap: { userSeq: true/false }
Map<String, bool> _userListMap = {}; Map<String, bool> _userListMap = {};
/// (1)
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.adUnitId;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -73,8 +71,6 @@ class _PlayingPrivatePageState extends State<PlayingPrivatePage> {
FirebaseDatabase.instance.goOnline(); FirebaseDatabase.instance.goOnline();
roomTitle = widget.roomTitle; roomTitle = widget.roomTitle;
// (C)
_initBannerAd();
// (D) // (D)
_initFirebase(); _initFirebase();
} }
@ -86,27 +82,6 @@ class _PlayingPrivatePageState extends State<PlayingPrivatePage> {
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);
},
onAdFailedToLoad: (Ad ad, LoadAdError err) {
ad.dispose();
},
),
request: const AdRequest(),
);
// load()
_bannerAd?.load();
}
Future<void> _initFirebase() async { Future<void> _initFirebase() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0'; mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0';
@ -192,6 +167,10 @@ class _PlayingPrivatePageState extends State<PlayingPrivatePage> {
'introduce_myself': uData['introduce_myself'] ?? '', 'introduce_myself': uData['introduce_myself'] ?? '',
'is_my_score': (uSeq.toString() == mySeq) ? 'Y' : 'N', 'is_my_score': (uSeq.toString() == mySeq) ? 'Y' : 'N',
}); });
if (uSeq.toString() == mySeq) {
myParticipantType = (uData['participant_type'] ?? '').toString().toUpperCase();
}
}); });
// //
@ -386,11 +365,13 @@ class _PlayingPrivatePageState extends State<PlayingPrivatePage> {
}, },
); );
if (confirm != true) return false; if (confirm != true) {
return false;
}
} }
// userList => false // userList => false
final userRef = _roomRef.child('userList').child(mySeq); final userRef = _roomRef.child('userList').child('_$mySeq');
await userRef.set(false); await userRef.set(false);
if (!mounted) return false; if (!mounted) return false;
@ -449,8 +430,7 @@ class _PlayingPrivatePageState extends State<PlayingPrivatePage> {
} }
Future<void> _onTapUser(Map<String, dynamic> userData) async { Future<void> _onTapUser(Map<String, dynamic> userData) async {
final pType = (userData['participant_type'] ?? '').toString().toUpperCase(); if (myParticipantType == 'ADMIN') {
if (pType == 'ADMIN') {
// //
await showDialog( await showDialog(
context: context, context: context,
@ -460,16 +440,6 @@ class _PlayingPrivatePageState extends State<PlayingPrivatePage> {
userData: userData, userData: userData,
), ),
); );
} else if (roomMasterYn == 'Y') {
// (PLAYER)
await showDialog(
context: context,
builder: (_) => ScoreEditDialog(
roomSeq: widget.roomSeq,
roomType: 'PRIVATE',
userData: userData,
),
);
} else { } else {
// //
await showDialog( await showDialog(
@ -552,14 +522,7 @@ class _PlayingPrivatePageState extends State<PlayingPrivatePage> {
), ),
], ],
), ),
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
), ),
); );
} }

View File

@ -9,8 +9,7 @@ import '../../plugins/api.dart';
import '../../dialogs/response_dialog.dart'; import '../../dialogs/response_dialog.dart';
import '../../dialogs/score_edit_dialog.dart'; import '../../dialogs/score_edit_dialog.dart';
import '../../dialogs/user_info_basic_dialog.dart'; import '../../dialogs/user_info_basic_dialog.dart';
import '../../plugins/admob.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../../config/config.dart'; import '../../config/config.dart';
class PlayingTeamPage extends StatefulWidget { class PlayingTeamPage extends StatefulWidget {
@ -60,14 +59,12 @@ class _PlayingTeamPageState extends State<PlayingTeamPage> {
// userListMap: { seq: true/false } // userListMap: { seq: true/false }
Map<String, bool> _userListMap = {}; Map<String, bool> _userListMap = {};
//
String myParticipantType = 'PLAYER';
// //
String scoreOpenRange = 'ALL'; String scoreOpenRange = 'ALL';
/// (1)
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.adUnitId;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -75,8 +72,6 @@ class _PlayingTeamPageState extends State<PlayingTeamPage> {
FirebaseDatabase.instance.goOnline(); FirebaseDatabase.instance.goOnline();
roomTitle = widget.roomTitle; roomTitle = widget.roomTitle;
// (C)
_initBannerAd();
// (D) // (D)
_initFirebase(); _initFirebase();
} }
@ -88,27 +83,6 @@ class _PlayingTeamPageState extends State<PlayingTeamPage> {
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);
},
onAdFailedToLoad: (Ad ad, LoadAdError err) {
ad.dispose();
},
),
request: const AdRequest(),
);
// load()
_bannerAd?.load();
}
Future<void> _initFirebase() async { Future<void> _initFirebase() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0'; mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0';
@ -191,6 +165,9 @@ class _PlayingTeamPageState extends State<PlayingTeamPage> {
'team_name': (uData['team_name'] ?? '').toString().toUpperCase(), 'team_name': (uData['team_name'] ?? '').toString().toUpperCase(),
'score': uData['score'] ?? 0, 'score': uData['score'] ?? 0,
}); });
if (uSeq.toString() == mySeq) {
myParticipantType = (uData['participant_type'] ?? '').toString().toUpperCase();
}
}); });
// & // &
@ -415,7 +392,7 @@ class _PlayingTeamPageState extends State<PlayingTeamPage> {
} }
// userList => false // userList => false
final userRef = _roomRef.child('userList').child(mySeq); final userRef = _roomRef.child('userList').child('_$mySeq');
await userRef.set(false); await userRef.set(false);
if (!mounted) return false; if (!mounted) return false;
@ -510,14 +487,7 @@ class _PlayingTeamPageState extends State<PlayingTeamPage> {
), ),
], ],
), ),
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
), ),
); );
} }
@ -616,17 +586,7 @@ class _PlayingTeamPageState extends State<PlayingTeamPage> {
} }
Future<void> _onTapUser(Map<String, dynamic> userData) async { Future<void> _onTapUser(Map<String, dynamic> userData) async {
final pType = (userData['participant_type'] ?? '').toString().toUpperCase(); if (myParticipantType == 'ADMIN') {
if (pType == 'ADMIN') {
await showDialog(
context: context,
builder: (_) => ScoreEditDialog(
roomSeq: widget.roomSeq,
roomType: 'TEAM',
userData: userData,
),
);
} else if (roomMasterYn == 'Y') {
await showDialog( await showDialog(
context: context, context: context,
builder: (_) => ScoreEditDialog( builder: (_) => ScoreEditDialog(

View File

@ -5,7 +5,7 @@ import 'room_search_list_page.dart';
import '../../config/config.dart'; import '../../config/config.dart';
// //
import 'package:google_mobile_ads/google_mobile_ads.dart'; // AdMob import '../../plugins/admob.dart';
class RoomSearchHomePage extends StatefulWidget { class RoomSearchHomePage extends StatefulWidget {
const RoomSearchHomePage({Key? key}) : super(key: key); const RoomSearchHomePage({Key? key}) : super(key: key);
@ -15,43 +15,32 @@ class RoomSearchHomePage extends StatefulWidget {
} }
class _RoomSearchHomePageState extends State<RoomSearchHomePage> { class _RoomSearchHomePageState extends State<RoomSearchHomePage> {
BannerAd? _bannerAd; //
bool _isBannerReady = false; // double scaleFactor = 1.0;
String adUnitId = Config.adUnitId;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// (C)
_initBannerAd();
} }
@override @override
void dispose() { void dispose() {
_bannerAd?.dispose();
super.dispose(); super.dispose();
} }
/// @override
void _initBannerAd() { void didChangeDependencies() {
_bannerAd = BannerAd( super.didChangeDependencies();
size: AdSize.banner, // _updateScaleFactor();
// adUnitId: 'ca-app-pub-3940256099942544/6300978111' () }
adUnitId: adUnitId, // / ID
listener: BannerAdListener(
onAdLoaded: (Ad ad) {
setState(() => _isBannerReady = true);
},
onAdFailedToLoad: (Ad ad, LoadAdError err) {
//
},
),
request: const AdRequest(),
);
// load() //
_bannerAd?.load(); void _updateScaleFactor() {
final screenWidth = MediaQuery.of(context).size.width;
const baseWidth = 450.0;
setState(() {
scaleFactor = (screenWidth / baseWidth).clamp(0.8, 1.2);
});
} }
@override @override
@ -70,14 +59,7 @@ class _RoomSearchHomePageState extends State<RoomSearchHomePage> {
), ),
// //
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
// : 3 ( / / ) // : 3 ( / / )
body: Center( body: Center(
@ -102,8 +84,8 @@ class _RoomSearchHomePageState extends State<RoomSearchHomePage> {
required String status, required String status,
}) { }) {
return SizedBox( return SizedBox(
width: 100, width: 100 * scaleFactor,
height: 100, height: 100 * scaleFactor,
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
// RoomSearchListPage로 , roomStatus // RoomSearchListPage로 , roomStatus

View File

@ -14,7 +14,7 @@ import '../room/finish_team_page.dart';
import '../../config/config.dart'; import '../../config/config.dart';
// //
import 'package:google_mobile_ads/google_mobile_ads.dart'; // AdMob import '../../plugins/admob.dart';
class RoomSearchListPage extends StatefulWidget { class RoomSearchListPage extends StatefulWidget {
final String roomStatus; // WAIT / RUNNING / FINISH final String roomStatus; // WAIT / RUNNING / FINISH
@ -37,20 +37,12 @@ class _RoomSearchListPageState extends State<RoomSearchListPage> {
late ScrollController _scrollController; late ScrollController _scrollController;
//
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.adUnitId;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_scrollController = ScrollController()..addListener(_onScroll); _scrollController = ScrollController()..addListener(_onScroll);
_fetchRoomList(isRefresh: true); _fetchRoomList(isRefresh: true);
// (C)
_initBannerAd();
} }
@override @override
@ -58,31 +50,9 @@ class _RoomSearchListPageState extends State<RoomSearchListPage> {
_scrollController.removeListener(_onScroll); _scrollController.removeListener(_onScroll);
_scrollController.dispose(); _scrollController.dispose();
_searchController.dispose(); _searchController.dispose();
_bannerAd?.dispose();
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);
},
onAdFailedToLoad: (Ad ad, LoadAdError err) {
ad.dispose();
},
),
request: const AdRequest(),
);
// load()
_bannerAd?.load();
}
void _onScroll() { void _onScroll() {
if (!_scrollController.hasClients) return; if (!_scrollController.hasClients) return;
final thresholdPixels = 200; final thresholdPixels = 200;
@ -236,14 +206,8 @@ class _RoomSearchListPageState extends State<RoomSearchListPage> {
), ),
), ),
// //
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
body: Column( body: Column(
children: [ children: [
// //

View File

@ -12,10 +12,12 @@ import '../../dialogs/user_info_private_dialog.dart';
import 'playing_private_page.dart'; import 'playing_private_page.dart';
// //
import 'package:google_mobile_ads/google_mobile_ads.dart'; import '../../plugins/admob.dart';
// //
import '../../config/config.dart'; import '../../config/config.dart';
//
import 'package:auto_size_text/auto_size_text.dart';
class WaitingRoomPrivatePage extends StatefulWidget { class WaitingRoomPrivatePage extends StatefulWidget {
final int roomSeq; final int roomSeq;
@ -74,14 +76,13 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
bool _roomTimeOut = false; bool _roomTimeOut = false;
String _roomExitYn = 'N'; String _roomExitYn = 'N';
/// (1)
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.adUnitId;
// SEQ // SEQ
String _masterSeqString = '0'; String _masterSeqString = '0';
//
double scaleFactor = 1.0;
double buttonScaleFactor = 1.0;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -89,8 +90,6 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
FirebaseDatabase.instance.goOnline(); FirebaseDatabase.instance.goOnline();
// (B) // (B)
_initRoomRef(); _initRoomRef();
// (C)
_initBannerAd();
} }
@override @override
@ -100,25 +99,20 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
super.dispose(); super.dispose();
} }
/// @override
void _initBannerAd() { void didChangeDependencies() {
_bannerAd = BannerAd( super.didChangeDependencies();
size: AdSize.banner, // _updateScaleFactor();
// adUnitId: 'ca-app-pub-3940256099942544/6300978111' () }
adUnitId: adUnitId, // / ID
listener: BannerAdListener(
onAdLoaded: (Ad ad) {
setState(() => _isBannerReady = true);
},
onAdFailedToLoad: (Ad ad, LoadAdError err) {
ad.dispose();
},
),
request: const AdRequest(),
);
// load() //
_bannerAd?.load(); void _updateScaleFactor() {
final screenWidth = MediaQuery.of(context).size.width;
const baseWidth = 450.0;
setState(() {
scaleFactor = (screenWidth / baseWidth).clamp(0.8, 1.2);
buttonScaleFactor = (screenWidth / baseWidth).clamp(0.6, 1.2);
});
} }
Future<void> _initRoomRef() async { Future<void> _initRoomRef() async {
@ -328,7 +322,7 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
final response = await Api.serverRequest(uri: '/room/score/game/leave', body: reqBody); final response = await Api.serverRequest(uri: '/room/score/game/leave', body: reqBody);
// result ok -> // result ok ->
} catch (e) { } catch (e) {
// await showResponseDialog(context, '오류', '방 나가기 처리 실패');
} }
if (mounted) { if (mounted) {
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false); Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => const MainPage()), (route) => false);
@ -410,7 +404,7 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
final me = _userList.firstWhere((u) => (u['user_seq'].toString() ?? '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 = '준비';
final btnStyle = ElevatedButton.styleFrom( final btnStyle = ElevatedButton.styleFrom(
backgroundColor: Colors.white, backgroundColor: Colors.white,
@ -428,7 +422,11 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _onOpenRoomSetting, onPressed: _onOpenRoomSetting,
child: const Text('방 설정'), child: AutoSizeText(
'방 설정',
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor),
),
), ),
), ),
), ),
@ -438,7 +436,11 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _readyButtonEnabled ? _onToggleReady : null, onPressed: _readyButtonEnabled ? _onToggleReady : null,
child: Text(readyLabel), child: AutoSizeText(
readyLabel,
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor, color: isReady ? Colors.red : Colors.black),
),
), ),
), ),
), ),
@ -448,7 +450,11 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _onGameStart, onPressed: _onGameStart,
child: const Text('게임 시작'), child: AutoSizeText(
scaleFactor==0.8 ? '시작' : '게임 시작',
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor),
),
), ),
), ),
), ),
@ -464,7 +470,11 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _onOpenRoomSetting, onPressed: _onOpenRoomSetting,
child: const Text('방 설정'), child: AutoSizeText(
'방 설정',
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor),
),
), ),
), ),
), ),
@ -474,7 +484,11 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _readyButtonEnabled ? _onToggleReady : null, onPressed: _readyButtonEnabled ? _onToggleReady : null,
child: Text(readyLabel), child: AutoSizeText(
readyLabel,
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor, color: isReady ? Colors.red : Colors.black),
),
), ),
), ),
), ),
@ -619,14 +633,8 @@ class _WaitingRoomPrivatePageState extends State<WaitingRoomPrivatePage> {
onPressed: () => _onLeaveRoom(), onPressed: () => _onLeaveRoom(),
), ),
), ),
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
body: _isLoading body: _isLoading
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: SingleChildScrollView( : SingleChildScrollView(

View File

@ -18,10 +18,12 @@ 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 '../../plugins/admob.dart';
// //
import '../../config/config.dart'; import '../../config/config.dart';
//
import 'package:auto_size_text/auto_size_text.dart';
class WaitingRoomTeamPage extends StatefulWidget { class WaitingRoomTeamPage extends StatefulWidget {
final int roomSeq; final int roomSeq;
@ -76,24 +78,37 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
bool _roomTimeOut = false; bool _roomTimeOut = false;
String _roomExitYn = 'N'; String _roomExitYn = 'N';
/// (1)
BannerAd? _bannerAd;
bool _isBannerReady = false; //
String adUnitId = Config.adUnitId;
// SEQ // SEQ
String _masterSeqString = '0'; String _masterSeqString = '0';
//
double scaleFactor = 1.0;
double buttonScaleFactor = 1.0;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
FirebaseDatabase.instance.goOnline(); FirebaseDatabase.instance.goOnline();
// (C)
_initBannerAd();
// (D) // (D)
_initRoomRef(); _initRoomRef();
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_updateScaleFactor();
}
//
void _updateScaleFactor() {
final screenWidth = MediaQuery.of(context).size.width;
const baseWidth = 450.0;
setState(() {
scaleFactor = (screenWidth / baseWidth).clamp(0.8, 1.2);
buttonScaleFactor = (screenWidth / baseWidth).clamp(0.6, 1.2);
});
}
Future<void> _initRoomRef() async { Future<void> _initRoomRef() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0'; mySeq = prefs.getInt('my_user_seq')?.toString() ?? '0';
@ -118,27 +133,6 @@ 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);
},
onAdFailedToLoad: (Ad ad, LoadAdError 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) {
@ -416,7 +410,7 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
final me = _userList.firstWhere((u) => (u['user_seq'].toString() ?? '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 = '준비';
final btnStyle = ElevatedButton.styleFrom( final btnStyle = ElevatedButton.styleFrom(
backgroundColor: Colors.white, backgroundColor: Colors.white,
@ -433,7 +427,11 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _onOpenRoomSetting, onPressed: _onOpenRoomSetting,
child: const Text('방 설정'), child: AutoSizeText(
'방 설정',
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor),
),
), ),
), ),
), ),
@ -443,7 +441,11 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _readyButtonEnabled ? _onToggleReady : null, onPressed: _readyButtonEnabled ? _onToggleReady : null,
child: Text(readyLabel), child: AutoSizeText(
readyLabel,
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor, color: isReady ? Colors.red : Colors.black),
),
), ),
), ),
), ),
@ -455,7 +457,11 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
onPressed: _isServerRequestLoading ? null : _onGameStart, onPressed: _isServerRequestLoading ? null : _onGameStart,
child: _isServerRequestLoading child: _isServerRequestLoading
? const CircularProgressIndicator() ? const CircularProgressIndicator()
: const Text('게임 시작'), : AutoSizeText(
scaleFactor==0.8 ? '시작' : '게임 시작',
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor),
),
), ),
), ),
), ),
@ -470,7 +476,11 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _onOpenRoomSetting, onPressed: _onOpenRoomSetting,
child: const Text('방 설정'), child: AutoSizeText(
'방 설정',
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor),
),
), ),
), ),
), ),
@ -480,7 +490,11 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
child: ElevatedButton( child: ElevatedButton(
style: btnStyle, style: btnStyle,
onPressed: _readyButtonEnabled ? _onToggleReady : null, onPressed: _readyButtonEnabled ? _onToggleReady : null,
child: Text(readyLabel), child: AutoSizeText(
readyLabel,
maxLines: 1,
style: TextStyle(fontSize: 14 * scaleFactor, color: isReady ? Colors.red : Colors.black),
),
), ),
), ),
), ),
@ -637,14 +651,8 @@ class _WaitingRoomTeamPageState extends State<WaitingRoomTeamPage> {
onPressed: () => _onLeaveRoom(), onPressed: () => _onLeaveRoom(),
), ),
), ),
bottomNavigationBar: _isBannerReady && _bannerAd != null bottomNavigationBar: AdBannerWidget(),
? Container(
color: Colors.white,
width: _bannerAd!.size.width.toDouble(),
height: _bannerAd!.size.height.toDouble(),
child: AdWidget(ad: _bannerAd!),
)
: SizedBox.shrink(), // or
body: _isLoading body: _isLoading
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: SingleChildScrollView( : SingleChildScrollView(

View File

@ -9,6 +9,7 @@ import '../../plugins/utils.dart';
import 'withdrawal_page.dart'; import 'withdrawal_page.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'dart:io'; import 'dart:io';
import '../room/main_page.dart';
// import 'package:path/path.dart'; // import 'package:path/path.dart';
class MyPage extends StatefulWidget { class MyPage extends StatefulWidget {
@ -47,13 +48,27 @@ class _MyPageState extends State<MyPage> {
final TextEditingController _introduceController = TextEditingController(); final TextEditingController _introduceController = TextEditingController();
String? _nicknameError; String? _nicknameError;
XFile? _image; // XFile? _image; //
String _oauthType = 'idpw'; //
//
double scaleFactor = 1.0;
double buttonScaleFactor = 1.0;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
//
_introduceController.text = '';
_fetchUserInfo(); _fetchUserInfo();
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_updateScaleFactor();
}
@override @override
void dispose() { void dispose() {
_nicknameController.dispose(); _nicknameController.dispose();
@ -70,10 +85,30 @@ class _MyPageState extends State<MyPage> {
super.dispose(); super.dispose();
} }
//
void _updateScaleFactor() {
final screenWidth = MediaQuery.of(context).size.width;
const baseWidth = 400.0;
setState(() {
scaleFactor = (screenWidth / baseWidth).clamp(0.8, 1.2);
buttonScaleFactor = (screenWidth / baseWidth).clamp(0.6, 1.2);
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return WillPopScope(
onWillPop: () async {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => const MainPage()),
(route) => false,
);
return false;
},
child: GestureDetector(
onTap: () { onTap: () {
// ,
if (isEditingNickname) { if (isEditingNickname) {
setState(() { setState(() {
user_nickname = _nicknameController.text; user_nickname = _nicknameController.text;
@ -108,6 +143,7 @@ class _MyPageState extends State<MyPage> {
_departmentFocusNode.unfocus(); _departmentFocusNode.unfocus();
}); });
} }
FocusScope.of(context).unfocus();
}, },
child: Scaffold( child: Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
@ -117,8 +153,11 @@ class _MyPageState extends State<MyPage> {
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black), icon: const Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pushAndRemoveUntil(
Navigator.pop(context); context,
MaterialPageRoute(builder: (_) => const MainPage()),
(route) => false,
);
}, },
), ),
), ),
@ -204,7 +243,8 @@ class _MyPageState extends State<MyPage> {
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Card( //
_oauthType == 'idpw' ? Card(
elevation: 4, elevation: 4,
color: Colors.white, color: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -263,9 +303,22 @@ class _MyPageState extends State<MyPage> {
], ],
), ),
), ),
) : Card(
elevation: 4,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
), ),
// child: const Padding(
if (_passwordError != null) padding: EdgeInsets.all(16.0),
child: Text(
'비밀번호: 소셜 로그인 계정은 비밀번호를 수정할 수 없습니다.',
style: TextStyle(fontSize: 16, color: Colors.black54),
),
),
),
//
if (_oauthType == 'idpw' && _passwordError != null)
Padding( Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
child: Text( child: Text(
@ -273,7 +326,11 @@ class _MyPageState extends State<MyPage> {
style: const TextStyle(color: Colors.red, fontSize: 12), style: const TextStyle(color: Colors.red, fontSize: 12),
), ),
), ),
const SizedBox(height: 16), //
_oauthType == 'idpw' ?
const SizedBox(height: 16)
: const SizedBox(),
_oauthType == 'idpw' ?
Card( Card(
elevation: 4, elevation: 4,
color: Colors.white, color: Colors.white,
@ -332,9 +389,13 @@ class _MyPageState extends State<MyPage> {
], ],
), ),
), ),
), )
: const SizedBox(), //
// //
const SizedBox(height: 8), _oauthType == 'idpw' ?
const SizedBox(height: 8)
: const SizedBox(),
_oauthType == 'idpw' ?
Text( Text(
(new_user_pw == confirmPassword) (new_user_pw == confirmPassword)
? '비밀번호가 일치합니다.' ? '비밀번호가 일치합니다.'
@ -343,7 +404,10 @@ class _MyPageState extends State<MyPage> {
fontSize: 16, fontSize: 16,
color: (new_user_pw == confirmPassword) ? Colors.green : Colors.red, color: (new_user_pw == confirmPassword) ? Colors.green : Colors.red,
), ),
), )
: const SizedBox(),
//
_oauthType == 'idpw' ?
Card( Card(
elevation: 4, elevation: 4,
color: Colors.white, color: Colors.white,
@ -403,9 +467,34 @@ class _MyPageState extends State<MyPage> {
], ],
), ),
), ),
)
: Card(
elevation: 4,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
), ),
// child: Padding(
if (_emailError != null) padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'이메일:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Expanded(
child: Text(
user_email, //
style: const TextStyle(fontSize: 18, color: Colors.black54),
),
),
],
),
),
),
//
if (_oauthType == 'idpw' && _emailError != null)
Padding( Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
child: Text( child: Text(
@ -525,7 +614,7 @@ class _MyPageState extends State<MyPage> {
), ),
const SizedBox(height: 8), // const SizedBox(height: 8), //
TextField( TextField(
controller: _introduceController..text = user_introduce_myself, // controller: _introduceController, //
maxLines: 5, // maxLines: 5, //
decoration: InputDecoration( decoration: InputDecoration(
hintText: '자신을 소개하는 내용을 입력하세요...', hintText: '자신을 소개하는 내용을 입력하세요...',
@ -554,7 +643,7 @@ class _MyPageState extends State<MyPage> {
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40), // borderRadius: BorderRadius.circular(40), //
), ),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 60), // padding: EdgeInsets.symmetric(vertical: 12 * scaleFactor, horizontal: 60 * scaleFactor), //
), ),
child: const Text( child: const Text(
'수정하기', '수정하기',
@ -578,7 +667,7 @@ class _MyPageState extends State<MyPage> {
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40), // borderRadius: BorderRadius.circular(40), //
), ),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 60), // padding: EdgeInsets.symmetric(vertical: 12 * scaleFactor, horizontal: 60 * scaleFactor), //
), ),
child: const Text( child: const Text(
'회원탈퇴', '회원탈퇴',
@ -592,12 +681,16 @@ class _MyPageState extends State<MyPage> {
), ),
), ),
), ),
),
); );
} }
Future<void> _fetchUserInfo() async { Future<void> _fetchUserInfo() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
String? authToken = prefs.getString('auth_token'); String? authToken = prefs.getString('auth_token');
setState(() {
_oauthType = prefs.getString('oauth_type') ?? 'idpw';
});
final response = await Api.serverRequest( final response = await Api.serverRequest(
uri: '/user/myinfo', uri: '/user/myinfo',
@ -616,6 +709,8 @@ class _MyPageState extends State<MyPage> {
user_department = jsonResponse['data']['department']; user_department = jsonResponse['data']['department'];
user_introduce_myself = jsonResponse['data']['introduce_myself']; user_introduce_myself = jsonResponse['data']['introduce_myself'];
user_profile_image = jsonResponse['data']['profile_img']; user_profile_image = jsonResponse['data']['profile_img'];
//
_introduceController.text = user_introduce_myself;
}); });
} else { } else {
showResponseDialog(context, '${jsonResponse['response_info']['msg_title']}', '${jsonResponse['response_info']['msg_content']}'); showResponseDialog(context, '${jsonResponse['response_info']['msg_title']}', '${jsonResponse['response_info']['msg_content']}');
@ -716,7 +811,9 @@ class _MyPageState extends State<MyPage> {
// //
void _showEditDialog() { void _showEditDialog() {
// confirmPassword // 1) 'idpw'
if (_oauthType == 'idpw') {
//
if (new_user_pw != '**********') { if (new_user_pw != '**********') {
if (!_isPasswordValidPattern(new_user_pw)) { if (!_isPasswordValidPattern(new_user_pw)) {
showResponseDialog(context, '수정하기 실패', '비밀번호 패턴을 확인해주세요.'); showResponseDialog(context, '수정하기 실패', '비밀번호 패턴을 확인해주세요.');
@ -724,9 +821,12 @@ class _MyPageState extends State<MyPage> {
} }
if (new_user_pw != confirmPassword) { if (new_user_pw != confirmPassword) {
showResponseDialog(context, '수정하기 실패', '비밀번호가 일치하지 않습니다.'); showResponseDialog(context, '수정하기 실패', '비밀번호가 일치하지 않습니다.');
return; // return; //
} }
} }
}
// 2) /
if (!_isEmailValid(user_email)) { if (!_isEmailValid(user_email)) {
showResponseDialog(context, '수정하기 실패', '이메일 형식을 확인해주세요.'); showResponseDialog(context, '수정하기 실패', '이메일 형식을 확인해주세요.');
return; return;
@ -741,51 +841,55 @@ class _MyPageState extends State<MyPage> {
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return AlertDialog(
backgroundColor: Colors.white, // backgroundColor: Colors.white, //
title: const Center( // title: Center( //
child: Text( child: Text(
'회원정보 수정', '회원정보 수정',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), // style: TextStyle(fontSize: 20 * scaleFactor, fontWeight: FontWeight.bold), //
), ),
), ),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, // mainAxisSize: MainAxisSize.min, //
children: [ children: [
const Center( // Center( //
child: Text( child: Text(
'회원정보를 수정합니다.', '회원정보를 수정합니다.',
style: TextStyle(fontSize: 16), // style: TextStyle(fontSize: 16 * scaleFactor), //
), ),
), ),
const SizedBox(height: 8), // const SizedBox(height: 8), //
const Center( // // --- ---
if (_oauthType == 'idpw') ...[
Center(
child: Text( child: Text(
'현재 비밀번호를 입력해주세요.', '현재 비밀번호를 입력해주세요.',
style: TextStyle(fontSize: 16), // style: TextStyle(fontSize: 16 * scaleFactor),
), ),
), ),
const SizedBox(height: 8), // const SizedBox(height: 8),
TextField( TextField(
obscureText: true, // obscureText: true,
decoration: InputDecoration( decoration: InputDecoration(
hintText: '현재 비밀번호', hintText: '현재 비밀번호',
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), // borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.black), // borderSide: const BorderSide(color: Colors.black),
), ),
contentPadding: const EdgeInsets.all(10), // contentPadding: const EdgeInsets.all(10),
), ),
onChanged: (value) { onChanged: (value) {
user_pw = value; // user_pw에 user_pw = value; // user_pw에
}, },
), ),
], ],
// --- ---
],
), ),
actions: [ actions: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, // mainAxisAlignment: MainAxisAlignment.spaceEvenly, //
children: [ children: [
SizedBox( SizedBox(
width: 100, // width: 100 * buttonScaleFactor, //
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
// //
@ -795,17 +899,16 @@ class _MyPageState extends State<MyPage> {
if (serverResponse['result'] == 'OK') { if (serverResponse['result'] == 'OK') {
final serverResponse1 = serverResponse['response']; final serverResponse1 = serverResponse['response'];
if (serverResponse1['result'] == 'OK') { if (serverResponse1['result'] == 'OK') {
showResponseDialog(context, '수정하기 성공', '회원정보가 성공적으로 수정되었습니다.'); await showResponseDialog(context, '수정하기 성공', '회원정보가 성공적으로 수정되었습니다.');
Navigator.of(context).pop(); // Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => const MyPage()), (route) => false);
Navigator.of(context).pop(); //
} else { } else {
showResponseDialog(context, '${serverResponse1['response_info']['msg_title']}', '${serverResponse1['response_info']['msg_content']}'); await showResponseDialog(context, '${serverResponse1['response_info']['msg_title']}', '${serverResponse1['response_info']['msg_content']}');
} }
} else { } else {
showResponseDialog(context, '수정하기 실패', '서버에 문제가 있습니다. 관리자에게 문의해주세요.'); await showResponseDialog(context, '수정하기 실패', '서버에 문제가 있습니다. 관리자에게 문의해주세요.');
} }
} catch (e) { } catch (e) {
showResponseDialog(context, '수정하기 실패', e.toString()); await showResponseDialog(context, '수정하기 실패', e.toString());
} }
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
@ -815,14 +918,14 @@ class _MyPageState extends State<MyPage> {
borderRadius: BorderRadius.circular(40), // borderRadius: BorderRadius.circular(40), //
), ),
), ),
child: const Text( child: Text(
'수정하기', '수정',
style: TextStyle(color: Colors.black, fontSize: 14), // style: TextStyle(color: Colors.black, fontSize: 14 * buttonScaleFactor), //
), ),
), ),
), ),
SizedBox( SizedBox(
width: 100, // width: 100 * buttonScaleFactor, //
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(); // Navigator.of(context).pop(); //
@ -834,9 +937,9 @@ class _MyPageState extends State<MyPage> {
borderRadius: BorderRadius.circular(40), // borderRadius: BorderRadius.circular(40), //
), ),
), ),
child: const Text( child: Text(
'취소', '취소',
style: TextStyle(color: Colors.black, fontSize: 14), // style: TextStyle(color: Colors.black, fontSize: 14 * buttonScaleFactor), //
), ),
), ),
), ),
@ -862,6 +965,7 @@ class _MyPageState extends State<MyPage> {
"department": user_department, // "department": user_department, //
"profile_img": user_profile_image, // "profile_img": user_profile_image, //
"introduce_myself": user_introduce_myself, // "introduce_myself": user_introduce_myself, //
"oauth_type": _oauthType, //
}, },
); );
@ -905,17 +1009,17 @@ class _MyPageState extends State<MyPage> {
if (serverResponse['result'] == 'OK') { if (serverResponse['result'] == 'OK') {
final serverResponse1 = serverResponse['response']; final serverResponse1 = serverResponse['response'];
if (serverResponse1['result'] == 'OK') { if (serverResponse1['result'] == 'OK') {
showResponseDialog(context, '업로드 성공', '프로필 이미지가 성공적으로 업로드되었습니다.'); await showResponseDialog(context, '업로드 성공', '프로필 이미지가 성공적으로 업로드되었습니다.');
// user_profile_image ( '/images' ) // user_profile_image ( '/images' )
setState(() { setState(() {
user_profile_image = serverResponse1['data']['img_src'].replaceFirst('/images', ''); // '/images' user_profile_image = serverResponse1['data']['img_src'].replaceFirst('/images', ''); // '/images'
}); });
} else { } else {
showResponseDialog(context, '${serverResponse1['response_info']['msg_title']}', '${serverResponse1['response_info']['msg_content']}'); await showResponseDialog(context, '${serverResponse1['response_info']['msg_title']}', '${serverResponse1['response_info']['msg_content']}');
} }
} else { } else {
showResponseDialog(context, '업로드 실패', '서버에 문제가 있습니다. 관리자에게 문의해주세요.'); await showResponseDialog(context, '업로드 실패', '서버에 문제가 있습니다. 관리자에게 문의해주세요.');
} }
} }
} }

View File

@ -15,9 +15,8 @@ class WithdrawalPage extends StatefulWidget {
} }
class _WithdrawalPageState extends State<WithdrawalPage> { class _WithdrawalPageState extends State<WithdrawalPage> {
bool _isAgreed = false; // bool _isAgreed = false; //
final TextEditingController _passwordController = TextEditingController(); // final TextEditingController _passwordController = TextEditingController(); //
String _oauthType = 'idpw'; String _oauthType = 'idpw';
@override @override
@ -36,7 +35,10 @@ class _WithdrawalPageState extends State<WithdrawalPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// oauth_type == 'google' => //
final screenWidth = MediaQuery.of(context).size.width;
// oauth_type == 'google'
final isGoogleUser = (_oauthType.toLowerCase() == 'google'); final isGoogleUser = (_oauthType.toLowerCase() == 'google');
return Scaffold( return Scaffold(
@ -49,18 +51,25 @@ class _WithdrawalPageState extends State<WithdrawalPage> {
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
), ),
), ),
body: Padding( // SingleChildScrollView
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
// Column이
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Text( const SizedBox(height: 20),
const Center(
child: Text(
'회원탈퇴를 진행합니다.\n현재 비밀번호를 입력해주세요.', '회원탈퇴를 진행합니다.\n현재 비밀번호를 입력해주세요.',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(fontSize: 18), style: TextStyle(fontSize: 18),
), ),
),
const SizedBox(height: 20), const SizedBox(height: 20),
//
//
if (!isGoogleUser) ...[ if (!isGoogleUser) ...[
TextField( TextField(
controller: _passwordController, controller: _passwordController,
@ -76,12 +85,13 @@ class _WithdrawalPageState extends State<WithdrawalPage> {
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: Colors.black54, width: 1), // border: Border.all(color: Colors.black54, width: 1),
borderRadius: BorderRadius.circular(10), // borderRadius: BorderRadius.circular(10),
), ),
padding: const EdgeInsets.all(16.0), // padding: const EdgeInsets.all(16.0),
child: const Text( child: const Text(
'[회원 탈퇴 안내]\n' '[회원 탈퇴 안내]\n'
'회원 탈퇴를 진행하시겠습니까?\n' '회원 탈퇴를 진행하시겠습니까?\n'
@ -94,15 +104,16 @@ class _WithdrawalPageState extends State<WithdrawalPage> {
), ),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Row( Row(
children: [ children: [
Checkbox( Checkbox(
value: _isAgreed, // value: _isAgreed,
activeColor: Colors.black, // activeColor: Colors.black,
checkColor: Colors.white, // checkColor: Colors.white,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
_isAgreed = value ?? false; // _isAgreed = value ?? false;
}); });
}, },
), ),
@ -115,41 +126,48 @@ class _WithdrawalPageState extends State<WithdrawalPage> {
], ],
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
ElevatedButton(
// "탈퇴하기"
Center(
child: ElevatedButton(
onPressed: () { onPressed: () {
//
_requestWithdrawal(_passwordController.text, _isAgreed); _requestWithdrawal(_passwordController.text, _isAgreed);
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.black54, // backgroundColor: Colors.black54,
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 60), // //
padding: EdgeInsets.symmetric(
vertical: 12,
horizontal: screenWidth * 0.15,
),
), ),
child: const Text( child: const Text(
'탈퇴하기', '탈퇴하기',
style: TextStyle(color: Colors.white, fontSize: 16), // style: TextStyle(color: Colors.white, fontSize: 16),
), ),
), ),
),
const SizedBox(height: 20),
], ],
), ),
), ),
),
); );
} }
Future<void> _requestWithdrawal(String password, bool isAgreed) async { Future<void> _requestWithdrawal(String password, bool isAgreed) async {
if (!isAgreed) { if (!isAgreed) {
//
showResponseDialog(context, '회원탈퇴 동의 확인', '회원탈퇴 동의 체크가 필요합니다.'); showResponseDialog(context, '회원탈퇴 동의 확인', '회원탈퇴 동의 체크가 필요합니다.');
return; return;
} }
// //
if (_oauthType != 'google' && password.isEmpty) { if (_oauthType != 'google' && password.isEmpty) {
//
showResponseDialog(context, '비밀번호 확인', '비밀번호를 입력해야 합니다.'); showResponseDialog(context, '비밀번호 확인', '비밀번호를 입력해야 합니다.');
return; return;
} }
// // ''
if (password.isEmpty) { if (password.isEmpty) {
password = ''; password = '';
} }
@ -157,7 +175,7 @@ class _WithdrawalPageState extends State<WithdrawalPage> {
final response = await Api.serverRequest( final response = await Api.serverRequest(
uri: '/user/withdraw/user', uri: '/user/withdraw/user',
body: { body: {
'user_pw': Utils.hashPassword(password), // 'user_pw': Utils.hashPassword(password),
'oauth_type': _oauthType, 'oauth_type': _oauthType,
}, },
); );
@ -165,17 +183,20 @@ class _WithdrawalPageState extends State<WithdrawalPage> {
if (response['result'] == 'OK') { if (response['result'] == 'OK') {
final serverResponse = response['response']; final serverResponse = response['response'];
if (serverResponse['result'] == 'OK') { if (serverResponse['result'] == 'OK') {
// // &
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove('auth_token'); // await prefs.remove('auth_token');
await showResponseDialog(context, '회원탈퇴 완료', '회원탈퇴가 완료되었습니다.'); await showResponseDialog(context, '회원탈퇴 완료', '회원탈퇴가 완료되었습니다.');
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
MaterialPageRoute(builder: (context) => const LoginPage()), // MaterialPageRoute(builder: (context) => const LoginPage()),
); );
} else { } else {
showResponseDialog(context, serverResponse['response_info']['msg_title'], serverResponse['response_info']['msg_content']); showResponseDialog(
context,
serverResponse['response_info']['msg_title'],
serverResponse['response_info']['msg_content'],
);
} }
} else { } else {
showResponseDialog(context, '회원탈퇴 실패', '서버에 문제가 있습니다. 관리자에게 문의해주세요.'); showResponseDialog(context, '회원탈퇴 실패', '서버에 문제가 있습니다. 관리자에게 문의해주세요.');

View File

@ -41,6 +41,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.11.0" version: "2.11.0"
auto_size_text:
dependency: "direct main"
description:
name: auto_size_text
sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:

View File

@ -1,7 +1,7 @@
name: allscore_app name: allscore_app
description: "A new Flutter project." description: "A new Flutter project."
publish_to: 'none' publish_to: 'none'
version: 1.0.0+1 version: 1.0.3+4
environment: environment:
sdk: ^3.6.0 sdk: ^3.6.0
@ -26,6 +26,7 @@ dependencies:
fluttertoast: ^8.0.9 fluttertoast: ^8.0.9
flutter_launcher_icons: ^0.12.0 flutter_launcher_icons: ^0.12.0
flutter_native_splash: ^2.2.15 flutter_native_splash: ^2.2.15
auto_size_text: ^3.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: