This commit is contained in:
2025-12-02 11:06:23 +09:00
parent bf40c42c2c
commit 22caf64855
34 changed files with 4594 additions and 505 deletions
@@ -6,20 +6,22 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<queries>
<intent>
<action android:name="android.speech.RecognitionService" />
+1 -1
View File
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+19 -1
View File
@@ -8,6 +8,8 @@ PODS:
- CwlCatchException (2.2.1):
- CwlCatchExceptionSupport (~> 2.2.1)
- CwlCatchExceptionSupport (2.2.1)
- device_info_plus (0.0.1):
- Flutter
- DKImagePickerController/Core (4.3.9):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
@@ -109,6 +111,8 @@ PODS:
- nanopb/encode (= 2.30910.0)
- nanopb/decode (2.30910.0)
- nanopb/encode (2.30910.0)
- network_info_plus (0.0.1):
- Flutter
- objective_c (0.0.1):
- Flutter
- permission_handler_apple (9.3.0):
@@ -155,10 +159,13 @@ PODS:
- webview_flutter_wkwebview (0.0.1):
- Flutter
- FlutterMacOS
- wifi_iot (0.0.1):
- Flutter
DEPENDENCIES:
- audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/darwin`)
- bonsoir_darwin (from `.symlinks/plugins/bonsoir_darwin/darwin`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
@@ -166,6 +173,7 @@ DEPENDENCIES:
- google_mobile_ads (from `.symlinks/plugins/google_mobile_ads/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
- network_info_plus (from `.symlinks/plugins/network_info_plus/ios`)
- objective_c (from `.symlinks/plugins/objective_c/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
@@ -173,6 +181,7 @@ DEPENDENCIES:
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
- wifi_iot (from `.symlinks/plugins/wifi_iot/ios`)
SPEC REPOS:
trunk:
@@ -203,6 +212,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/audioplayers_darwin/darwin"
bonsoir_darwin:
:path: ".symlinks/plugins/bonsoir_darwin/darwin"
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
@@ -217,6 +228,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/image_picker_ios/ios"
mobile_scanner:
:path: ".symlinks/plugins/mobile_scanner/ios"
network_info_plus:
:path: ".symlinks/plugins/network_info_plus/ios"
objective_c:
:path: ".symlinks/plugins/objective_c/ios"
permission_handler_apple:
@@ -231,12 +244,15 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher_ios/ios"
webview_flutter_wkwebview:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
wifi_iot:
:path: ".symlinks/plugins/wifi_iot/ios"
SPEC CHECKSUMS:
audioplayers_darwin: 4027b33a8f471d996c13f71cb77f0b1583b5d923
bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842
CwlCatchException: 7acc161b299a6de7f0a46a6ed741eae2c8b4d75a
CwlCatchExceptionSupport: 54ccab8d8c78907b57f99717fb19d4cc3bce02dc
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
@@ -259,6 +275,7 @@ SPEC CHECKSUMS:
MLKitVision: e858c5f125ecc288e4a31127928301eaba9ae0c1
mobile_scanner: 96e91f2e1fb396bb7df8da40429ba8dfad664740
nanopb: 438bc412db1928dac798aa6fd75726007be04262
network_info_plus: 9d930145451916919786087c4173226363616071
objective_c: 77e887b5ba1827970907e10e832eec1683f3431d
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
@@ -270,7 +287,8 @@ SPEC CHECKSUMS:
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa
webview_flutter_wkwebview: 29eb20d43355b48fe7d07113835b9128f84e3af4
wifi_iot: b5aafd6f9b52f8a357383a1deabab45f31cd602d
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
PODFILE CHECKSUM: 251cb053df7158f337c0712f2ab29f4e0fa474ce
COCOAPODS: 1.16.2
@@ -63,6 +63,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A0F77A962ED7E5CF0058AC51 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
D4D50D0F4B952368E1319826 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
F6B684F378DF7FE6F2C3CABC /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -139,6 +140,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
A0F77A962ED7E5CF0058AC51 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@@ -161,7 +163,6 @@
4E75157E0476F57C9A36AAFF /* Pods-RunnerTests.release.xcconfig */,
7CAA68E8ECB59955A38AF698 /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
@@ -488,6 +489,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = TDVYRQ3Z3E;
ENABLE_BITCODE = NO;
@@ -671,6 +673,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = TDVYRQ3Z3E;
ENABLE_BITCODE = NO;
@@ -694,6 +697,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = TDVYRQ3Z3E;
ENABLE_BITCODE = NO;
+12
View File
@@ -50,6 +50,7 @@
<key>NSBonjourServices</key>
<array>
<string>_playwith._tcp</string>
<string>_playwith._udp</string>
</array>
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string>
@@ -67,5 +68,16 @@
<string>정답을 음성으로 말하기 위해 마이크 권한이 필요합니다.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>말한 내용을 텍스트로 변환하여 정답을 확인합니다.</string>
<key>com.apple.developer.networking.wifi-info</key>
<true/>
<key>NEHotspotConfiguration</key>
<true/>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>주변 친구를 찾기 위해 블루투스를 사용합니다.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>주변 친구를 찾기 위해 블루투스를 사용합니다.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>로컬 통신을 위해 필요합니다.</string>
</dict>
</plist>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.networking.HotspotConfiguration</key>
<true/>
</dict>
</plist>
+299 -126
View File
@@ -1,10 +1,14 @@
import 'dart:convert';
import 'dart:io';
import 'package:bonsoir/bonsoir.dart';
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:playwith_core/playwith_core.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:wifi_iot/wifi_iot.dart';
import 'package:network_info_plus/network_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';
class LobbyScreen extends StatefulWidget {
const LobbyScreen({super.key});
@@ -28,7 +32,6 @@ class _LobbyScreenState extends State<LobbyScreen> {
_logs.add(log);
if (_logs.length > 100) _logs.removeAt(0);
});
if (SettingsNotifier().isShowDebugLog) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_scrollController.hasClients) {
@@ -45,40 +48,89 @@ class _LobbyScreenState extends State<LobbyScreen> {
_net.messageStream.listen((data) {
if (data['type'] == 'GAME_START') {
final String gameId = data['gameId'];
if (gameId == 'quiz_ox' || gameId == 'quiz_mix') {
_startGameAndNavigate(QuizGame());
}
else if (gameId == 'sudoku_battle') {
_startGameAndNavigate(SudokuMultiGame());
}
else if (gameId == 'spider_battle') {
_startGameAndNavigate(SpiderMultiGame());
}
// [추가] 오목 & 장기 연결
else if (gameId == 'omok') {
_startGameAndNavigate(OmokGame());
}
else if (gameId == 'janggi') {
_startGameAndNavigate(JanggiGame());
}
else if (gameId == 'yutnori') {
_startGameAndNavigate(YutnoriGame());
}
else if (gameId == 'memory_battle') {
_startGameAndNavigate(MemoryGame());
}
// [추가] 밸런스 & 터치 배틀 연결
else if (gameId == 'balance_game') {
_startGameAndNavigate(BalanceGame());
}
else if (gameId == 'tap_battle') {
_startGameAndNavigate(TapBattleGame());
}
_routeToGame(gameId);
}
});
}
Future<int?> _showSpiderDifficultyDialog() {
return showDialog<int>(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: const Text("스파이더 난이도"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: const Text("초급 (1가지 무늬)"),
subtitle: const Text("스페이드만 사용"),
leading: const Icon(Icons.looks_one, color: Colors.green),
onTap: () => Navigator.pop(context, 1),
),
ListTile(
title: const Text("중급 (2가지 무늬)"),
subtitle: const Text("스페이드 + 하트"),
leading: const Icon(Icons.looks_two, color: Colors.orange),
onTap: () => Navigator.pop(context, 2),
),
ListTile(
title: const Text("고급 (4가지 무늬)"),
subtitle: const Text("모든 무늬 사용"),
leading: const Icon(Icons.looks_4, color: Colors.red),
onTap: () => Navigator.pop(context, 4),
),
],
),
actions: [TextButton(onPressed: () => Navigator.pop(context, null), child: const Text("취소"))],
),
);
}
void _routeToGame(String gameId) {
if (gameId == 'quiz_ox' || gameId == 'quiz_mix') {
_startGameAndNavigate(QuizGame());
} else if (gameId == 'sudoku_battle') {
_startGameAndNavigate(SudokuMultiGame());
} else if (gameId == 'spider_battle') {
_startGameAndNavigate(SpiderMultiGame());
} else if (gameId == 'omok') {
_startGameAndNavigate(OmokGame());
} else if (gameId == 'janggi') {
_startGameAndNavigate(JanggiGame());
} else if (gameId == 'yutnori') {
_startGameAndNavigate(YutnoriGame());
} else if (gameId == 'memory_battle') {
_startGameAndNavigate(MemoryGame());
} else if (gameId == 'balance_game') {
_startGameAndNavigate(BalanceGame());
} else if (gameId == 'tap_battle') {
_startGameAndNavigate(TapBattleGame());
} else if (gameId == 'world_tour') {
_startGameAndNavigate(WorldTourGame());
} else if (gameId == 'othello') {
_startGameAndNavigate(OthelloGame());
} else if (gameId == 'arkanoid') {
_startGameAndNavigate(ArkanoidGame());
}else if (gameId == 'math_run') {
_startGameAndNavigate(MathRunGame());
}
else if (gameId == 'jump_battle') {
_startGameAndNavigate(JumpGame());
}
// [추가] 아이엠그라운드 연결
else if (gameId == 'iam_ground') {
_startGameAndNavigate(IAmGroundGame());
}
else if (gameId == 'survivor') {
_startGameAndNavigate(SurvivorGame());
}
else if (gameId == 'sequence_memory') {
_startGameAndNavigate(SequenceMemoryGame());
}
}
Future<void> _startGameAndNavigate(BaseGame game) async {
if (!mounted) return;
game.onStart();
@@ -96,7 +148,6 @@ class _LobbyScreenState extends State<LobbyScreen> {
children: [
gameView,
const SafeArea(
// 배너 광고 높이만큼 띄워서 채팅창 표시
child: GameChatOverlay(bottomOffset: 60.0),
),
],
@@ -104,8 +155,6 @@ class _LobbyScreenState extends State<LobbyScreen> {
}),
);
// [수정] 게임 종료 후 복귀 시 로직
// 솔로 모드였다면 네트워크를 종료하고 초기 화면으로 돌아감
if (_net.hostIp == "Solo Mode") {
_net.stopNetwork();
}
@@ -117,16 +166,21 @@ class _LobbyScreenState extends State<LobbyScreen> {
MaterialPageRoute(
builder: (context) => GameSelectionScreen(
onGameSelected: (gameId) async {
// 스도쿠 선택 시 난이도 팝업
Map<String, dynamic> config = {};
if (gameId == 'sudoku_battle') {
final difficulty = await _showDifficultyDialog();
if (difficulty == null) return; // 취소함
if (difficulty == null) return;
config['difficulty'] = difficulty;
}
// [추가] 스파이더 난이도
else if (gameId == 'spider_battle') {
final suits = await _showSpiderDifficultyDialog();
if (suits == null) return;
config['difficulty'] = suits; // numSuits (1, 2, 4)
}
if (!mounted) return;
Navigator.pop(context); // 선택 화면 닫기
Navigator.pop(context);
if (isSolo) {
_net.startSoloMode(gameId, config: config);
@@ -144,7 +198,6 @@ class _LobbyScreenState extends State<LobbyScreen> {
);
}
// [추가] 난이도 선택 다이얼로그
Future<int?> _showDifficultyDialog() {
return showDialog<int>(
context: context,
@@ -154,39 +207,44 @@ class _LobbyScreenState extends State<LobbyScreen> {
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: const Text("쉬움"),
leading: const Icon(Icons.filter_1, color: Colors.green),
onTap: () => Navigator.pop(context, 4),
),
ListTile(
title: const Text("보통"),
leading: const Icon(Icons.filter_2, color: Colors.blue),
onTap: () => Navigator.pop(context, 5), // 4~5 레벨이 보통 9x9
),
ListTile(
title: const Text("약간 어려움"),
leading: const Icon(Icons.filter_3, color: Colors.red),
onTap: () => Navigator.pop(context, 6), // 7 레벨이 어려움
),
ListTile(
title: const Text("약간 어려움"),
leading: const Icon(Icons.filter_4, color: Colors.red),
onTap: () => Navigator.pop(context, 7), // 7 레벨이 어려움
),
ListTile(
title: const Text("개 어려움"),
leading: const Icon(Icons.filter_5, color: Colors.red),
onTap: () => Navigator.pop(context, 8), // 7 레벨이 어려움
),
ListTile(title: const Text("쉬움 (4x4)"), onTap: () => Navigator.pop(context, 1)),
ListTile(title: const Text("보통 (9x9)"), onTap: () => Navigator.pop(context, 4)),
ListTile(title: const Text("어려움 (9x9)"), onTap: () => Navigator.pop(context, 7)),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, null),
child: const Text("취소"),
)
],
actions: [TextButton(onPressed: () => Navigator.pop(context), child: const Text("취소"))],
),
);
}
void _openGameSelector() {
if (_net.role != NetworkRole.host) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GameSelectionScreen(
onGameSelected: (gameId) async {
Map<String, dynamic> config = {};
if (gameId == 'sudoku_battle') {
final difficulty = await _showDifficultyDialog();
if (difficulty == null) return;
config['difficulty'] = difficulty;
}
else if (gameId == 'spider_battle') {
final suits = await _showSpiderDifficultyDialog();
if (suits == null) return;
config['difficulty'] = suits;
}
if (!mounted) return;
Navigator.pop(context);
if (_net.role == NetworkRole.host) {
_net.selectGame(gameId, config: config);
}
},
),
),
);
}
@@ -228,9 +286,7 @@ class _LobbyScreenState extends State<LobbyScreen> {
: _buildLobbyView()
),
const Divider(thickness: 1, height: 1),
if (SettingsNotifier().isShowDebugLog)
_buildDebugConsole(),
if (SettingsNotifier().isShowDebugLog) _buildDebugConsole(),
],
),
);
@@ -297,23 +353,33 @@ class _LobbyScreenState extends State<LobbyScreen> {
Widget _buildLobbyView() {
final currentGame = AppGames.getById(_net.selectedGameId);
final bool isHost = _net.role == NetworkRole.host;
return Column(
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20),
color: Colors.indigo.withOpacity(0.1),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(currentGame.icon, size: 20, color: Colors.indigo),
const SizedBox(width: 8),
Text(
"선택된 게임: ${currentGame.name}",
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.indigo),
),
],
GestureDetector(
onTap: isHost ? _openGameSelector : null,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20),
color: Colors.indigo.withOpacity(0.1),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(currentGame.icon, size: 24, color: Colors.indigo),
const SizedBox(width: 10),
Column(
children: [
Text(
"현재 게임: ${currentGame.name}",
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.indigo),
),
if (isHost)
const Text("(눌러서 변경)", style: TextStyle(fontSize: 12, color: Colors.grey)),
],
),
],
),
),
),
@@ -326,15 +392,15 @@ class _LobbyScreenState extends State<LobbyScreen> {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(_net.role == NetworkRole.host ? Icons.wifi_tethering : Icons.wifi, color: Colors.blue),
Icon(isHost ? Icons.wifi_tethering : Icons.wifi, color: Colors.blue),
const SizedBox(width: 10),
Text(
_net.role == NetworkRole.host ? "👑 방장 (나)" : "참가자 (나)",
isHost ? "👑 방장 (나)" : "참가자 (나)",
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
if (_net.role == NetworkRole.host) ...[
if (isHost) ...[
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
@@ -350,8 +416,11 @@ class _LobbyScreenState extends State<LobbyScreen> {
)
],
),
const SizedBox(height: 5),
const Text("QR 코드를 눌러 친구를 초대하세요!", style: TextStyle(fontSize: 12, color: Colors.grey)),
TextButton.icon(
icon: const Icon(Icons.wifi_password),
label: const Text("핫스팟(야외용) QR 만들기"),
onPressed: () => _showHotspotCreateDialog(),
),
] else ...[
const SizedBox(height: 10),
Text("방장 IP: ${_net.hostIp ?? '...'}", style: const TextStyle(color: Colors.grey)),
@@ -369,7 +438,7 @@ class _LobbyScreenState extends State<LobbyScreen> {
_buildUserTile(_net.me, isMe: true),
..._net.guestList.map((guest) => _buildUserTile(guest, isMe: false)),
if (_net.guestList.isEmpty && _net.role == NetworkRole.host)
if (_net.guestList.isEmpty && isHost)
const Padding(
padding: EdgeInsets.all(40.0),
child: Center(child: Text("참가자를 기다리는 중...\nQR 코드를 보여주세요.", textAlign: TextAlign.center, style: TextStyle(color: Colors.grey))),
@@ -412,6 +481,7 @@ class _LobbyScreenState extends State<LobbyScreen> {
Widget _buildReadyButton() {
bool isReady = _net.me.isReady;
bool canReady = _net.role == NetworkRole.host ? _net.guestList.isNotEmpty : true;
if (_net.hostIp == "Solo Mode") canReady = true;
return Container(
width: double.infinity,
@@ -466,10 +536,52 @@ class _LobbyScreenState extends State<LobbyScreen> {
);
}
void _showHotspotCreateDialog() {
final ssidCtrl = TextEditingController();
final pwCtrl = TextEditingController();
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text("핫스팟 QR 만들기"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text("스마트폰 설정에서 핫스팟을 켜고,\n그 정보를 입력해주세요.", style: TextStyle(fontSize: 12, color: Colors.grey)),
const SizedBox(height: 10),
TextField(controller: ssidCtrl, decoration: const InputDecoration(labelText: "핫스팟 이름 (SSID)")),
TextField(controller: pwCtrl, decoration: const InputDecoration(labelText: "비밀번호")),
],
),
actions: [
TextButton(onPressed: () => Navigator.pop(ctx), child: const Text("취소")),
ElevatedButton(
onPressed: () {
if (ssidCtrl.text.isEmpty) return;
Navigator.pop(ctx);
final Map<String, dynamic> qrData = {
'type': 'hotspot_invite',
'ssid': ssidCtrl.text,
'pwd': pwCtrl.text,
'port': _net.hostPort ?? 0,
};
_showGeneratedQR(jsonEncode(qrData), "핫스팟 + 게임 접속 QR");
},
child: const Text("생성"),
)
],
),
);
}
void _showHostQRDialog() {
if (_net.hostIp == null || _net.hostPort == null) return;
final qrData = jsonEncode({'ip': _net.hostIp, 'port': _net.hostPort});
_showGeneratedQR(qrData, "초대 QR 코드 (같은 와이파이)");
}
void _showGeneratedQR(String data, String title) {
showDialog(
context: context,
builder: (context) => Dialog(
@@ -479,16 +591,14 @@ class _LobbyScreenState extends State<LobbyScreen> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text("초대 QR 코드", style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
Text(title, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(border: Border.all(color: Colors.black12), borderRadius: BorderRadius.circular(10)),
child: QrImageView(data: qrData, version: QrVersions.auto, size: 220.0),
child: QrImageView(data: data, version: QrVersions.auto, size: 220.0),
),
const SizedBox(height: 20),
SelectableText("IP: ${_net.hostIp}\nPort: ${_net.hostPort}", textAlign: TextAlign.center, style: const TextStyle(color: Colors.grey)),
const SizedBox(height: 20),
ElevatedButton(onPressed: () => Navigator.pop(context), child: const Text("닫기"))
],
),
@@ -497,34 +607,6 @@ class _LobbyScreenState extends State<LobbyScreen> {
);
}
void _openQRScanner() {
bool isScanCompleted = false;
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(title: const Text("QR 스캔")),
body: MobileScanner(
onDetect: (capture) {
if (isScanCompleted) return;
for (final barcode in capture.barcodes) {
if (barcode.rawValue != null) {
try {
final data = jsonDecode(barcode.rawValue!);
if (data['ip'] != null && data['port'] != null) {
isScanCompleted = true;
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("접속 중...")));
_net.joinRoom(data['ip'], data['port']);
return;
}
} catch (e) {}
}
}
},
),
),
));
}
void _showRoomListDialog() {
showDialog(
context: context,
@@ -565,6 +647,97 @@ class _LobbyScreenState extends State<LobbyScreen> {
);
}
void _openQRScanner() {
bool isScanCompleted = false;
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(title: const Text("QR 스캔")),
body: MobileScanner(
onDetect: (capture) async {
if (isScanCompleted) return;
final List<Barcode> barcodes = capture.barcodes;
for (final barcode in barcodes) {
final String? rawValue = barcode.rawValue;
if (rawValue == null) continue;
try {
final data = jsonDecode(rawValue);
// 핫스팟 자동 접속
if (data['type'] == 'hotspot_invite') {
isScanCompleted = true;
await _connectToHotspotAndJoin(
data['ssid'],
data['pwd'],
data['port']
);
return;
}
// 일반 게임 접속
if (data['ip'] != null && data['port'] != null) {
isScanCompleted = true;
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("접속 중...")));
_net.joinRoom(data['ip'], data['port']);
return;
}
} catch (e) {
// JSON 아님
}
}
},
),
),
));
}
Future<void> _connectToHotspotAndJoin(String ssid, String pwd, int port) async {
if (Platform.isAndroid) {
var status = await Permission.location.request();
if (!status.isGranted) return;
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("핫스팟 '$ssid' 연결 시도 중...")),
);
try {
bool connected = await WiFiForIoTPlugin.connect(
ssid,
password: pwd,
security: NetworkSecurity.WPA,
joinOnce: true,
withInternet: false,
);
if (connected) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("와이파이 연결 성공! 방장을 찾는 중...")),
);
final info = NetworkInfo();
String? gatewayIp = await info.getWifiGatewayIP();
if (gatewayIp != null) {
await Future.delayed(const Duration(seconds: 1));
if (!mounted) return;
Navigator.pop(context);
_net.joinRoom(gatewayIp, port);
} else {
throw Exception("방장 IP를 찾을 수 없습니다.");
}
} else {
throw Exception("와이파이 연결 실패.");
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("오류: $e")),
);
}
}
void _showManualJoinDialog() {
final ipCtrl = TextEditingController(text: "192.168.");
final portCtrl = TextEditingController();
@@ -7,11 +7,13 @@ import Foundation
import audioplayers_darwin
import bonsoir_darwin
import device_info_plus
import file_picker
import file_selector_macos
import flutter_local_notifications
import gal
import mobile_scanner
import network_info_plus
import shared_preferences_foundation
import speech_to_text
import sqlite3_flutter_libs
@@ -21,11 +23,13 @@ import webview_flutter_wkwebview
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
SwiftBonsoirPlugin.register(with: registry.registrar(forPlugin: "SwiftBonsoirPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin"))
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SpeechToTextPlugin.register(with: registry.registrar(forPlugin: "SpeechToTextPlugin"))
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
+1 -1
View File
@@ -1,4 +1,4 @@
platform :osx, '10.15'
platform :osx, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+136
View File
@@ -0,0 +1,136 @@
PODS:
- audioplayers_darwin (0.0.1):
- Flutter
- FlutterMacOS
- bonsoir_darwin (0.0.1):
- Flutter
- FlutterMacOS
- CwlCatchException (2.2.1):
- CwlCatchExceptionSupport (~> 2.2.1)
- CwlCatchExceptionSupport (2.2.1)
- file_picker (0.0.1):
- FlutterMacOS
- file_selector_macos (0.0.1):
- FlutterMacOS
- flutter_local_notifications (0.0.1):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- gal (1.0.0):
- Flutter
- FlutterMacOS
- mobile_scanner (5.2.3):
- FlutterMacOS
- objective_c (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- speech_to_text (7.2.0):
- CwlCatchException
- Flutter
- FlutterMacOS
- sqlite3 (3.50.4):
- sqlite3/common (= 3.50.4)
- sqlite3/common (3.50.4)
- sqlite3/dbstatvtab (3.50.4):
- sqlite3/common
- sqlite3/fts5 (3.50.4):
- sqlite3/common
- sqlite3/math (3.50.4):
- sqlite3/common
- sqlite3/perf-threadsafe (3.50.4):
- sqlite3/common
- sqlite3/rtree (3.50.4):
- sqlite3/common
- sqlite3/session (3.50.4):
- sqlite3/common
- sqlite3_flutter_libs (0.0.1):
- Flutter
- FlutterMacOS
- sqlite3 (~> 3.50.4)
- sqlite3/dbstatvtab
- sqlite3/fts5
- sqlite3/math
- sqlite3/perf-threadsafe
- sqlite3/rtree
- sqlite3/session
- url_launcher_macos (0.0.1):
- FlutterMacOS
- webview_flutter_wkwebview (0.0.1):
- Flutter
- FlutterMacOS
DEPENDENCIES:
- audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/darwin`)
- bonsoir_darwin (from `Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin`)
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
- flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`)
- mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos`)
- objective_c (from `Flutter/ephemeral/.symlinks/plugins/objective_c/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- speech_to_text (from `Flutter/ephemeral/.symlinks/plugins/speech_to_text/darwin`)
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- webview_flutter_wkwebview (from `Flutter/ephemeral/.symlinks/plugins/webview_flutter_wkwebview/darwin`)
SPEC REPOS:
trunk:
- CwlCatchException
- CwlCatchExceptionSupport
- sqlite3
EXTERNAL SOURCES:
audioplayers_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/darwin
bonsoir_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin
file_picker:
:path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos
file_selector_macos:
:path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
flutter_local_notifications:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos
FlutterMacOS:
:path: Flutter/ephemeral
gal:
:path: Flutter/ephemeral/.symlinks/plugins/gal/darwin
mobile_scanner:
:path: Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos
objective_c:
:path: Flutter/ephemeral/.symlinks/plugins/objective_c/macos
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
speech_to_text:
:path: Flutter/ephemeral/.symlinks/plugins/speech_to_text/darwin
sqlite3_flutter_libs:
:path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
webview_flutter_wkwebview:
:path: Flutter/ephemeral/.symlinks/plugins/webview_flutter_wkwebview/darwin
SPEC CHECKSUMS:
audioplayers_darwin: 4027b33a8f471d996c13f71cb77f0b1583b5d923
bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842
CwlCatchException: 7acc161b299a6de7f0a46a6ed741eae2c8b4d75a
CwlCatchExceptionSupport: 54ccab8d8c78907b57f99717fb19d4cc3bce02dc
file_picker: e716a70a9fe5fd9e09ebc922d7541464289443af
file_selector_macos: 3e56eaea051180007b900eacb006686fd54da150
flutter_local_notifications: 4b427ffabf278fc6ea9484c97505e231166927a5
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5
mobile_scanner: 0a05256215b047af27b9495db3b77640055e8824
objective_c: e5f8194456e8fc943e034d1af00510a1bc29c067
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
speech_to_text: 87bf9298952e8d9073be1b6aade6d5758db5170c
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
sqlite3_flutter_libs: 86f82662868ee26ff3451f73cac9c5fc2a1f57fa
url_launcher_macos: 175a54c831f4375a6cf895875f716ee5af3888ce
webview_flutter_wkwebview: 29eb20d43355b48fe7d07113835b9128f84e3af4
PODFILE CHECKSUM: 1e95c36afbfd1cb6423ceca4de7a8e1b256fb6ac
COCOAPODS: 1.16.2
@@ -21,12 +21,14 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
16081A8E490D05A0EB9DCB3B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C20AF64D20A0D998576B7391 /* Pods_Runner.framework */; };
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
868F63F0C0F04AA311C4DEB8 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AA200BBA16E846EF02EA220 /* Pods_RunnerTests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -60,11 +62,12 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
2FD6D31AB2013B75CB16C72F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* playwith_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "playwith_app.app"; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10ED2044A3C60003C045 /* playwith_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = playwith_app.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -76,8 +79,15 @@
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
5CCBBFA4C427193DF37044DA /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
5F844C09FCD307AF262BDB41 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
86F5450344B9BE2273976B6B /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
8AA200BBA16E846EF02EA220 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8B9DF8C58AFF7B81844064AC /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
BD1BC5FF85A673AC7738F6DF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
C20AF64D20A0D998576B7391 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -85,6 +95,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
868F63F0C0F04AA311C4DEB8 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -92,6 +103,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
16081A8E490D05A0EB9DCB3B /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -125,6 +137,7 @@
331C80D6294CF71000263BE5 /* RunnerTests */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
855AC529D1809DF3B555D40F /* Pods */,
);
sourceTree = "<group>";
};
@@ -172,9 +185,25 @@
path = Runner;
sourceTree = "<group>";
};
855AC529D1809DF3B555D40F /* Pods */ = {
isa = PBXGroup;
children = (
5F844C09FCD307AF262BDB41 /* Pods-Runner.debug.xcconfig */,
2FD6D31AB2013B75CB16C72F /* Pods-Runner.release.xcconfig */,
BD1BC5FF85A673AC7738F6DF /* Pods-Runner.profile.xcconfig */,
5CCBBFA4C427193DF37044DA /* Pods-RunnerTests.debug.xcconfig */,
86F5450344B9BE2273976B6B /* Pods-RunnerTests.release.xcconfig */,
8B9DF8C58AFF7B81844064AC /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
C20AF64D20A0D998576B7391 /* Pods_Runner.framework */,
8AA200BBA16E846EF02EA220 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -186,6 +215,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
289049F07BF5608C0DEEA906 /* [CP] Check Pods Manifest.lock */,
331C80D1294CF70F00263BE5 /* Sources */,
331C80D2294CF70F00263BE5 /* Frameworks */,
331C80D3294CF70F00263BE5 /* Resources */,
@@ -204,11 +234,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
772657A59DCC9D8E14DB7114 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
C8ACC0A85F9FDC2B7315ABC5 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -291,6 +323,28 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
289049F07BF5608C0DEEA906 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -329,6 +383,45 @@
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
772657A59DCC9D8E14DB7114 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C8ACC0A85F9FDC2B7315ABC5 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -380,6 +473,7 @@
/* Begin XCBuildConfiguration section */
331C80DB294CF71000263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5CCBBFA4C427193DF37044DA /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
@@ -394,6 +488,7 @@
};
331C80DC294CF71000263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 86F5450344B9BE2273976B6B /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
@@ -408,6 +503,7 @@
};
331C80DD294CF71000263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8B9DF8C58AFF7B81844064AC /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
@@ -4,4 +4,7 @@
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
+64 -7
View File
@@ -185,6 +185,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.11"
device_info_plus:
dependency: transitive
description:
name: device_info_plus
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
url: "https://pub.dev"
source: hosted
version: "10.1.2"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
url: "https://pub.dev"
source: hosted
version: "7.0.3"
drift:
dependency: transitive
description:
@@ -504,6 +520,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.2.3"
nearby_connections:
dependency: transitive
description:
name: nearby_connections
sha256: "94d500bdb11f9a3db3b1cb2949ab438107e581f0142380efc17ecc8038e99369"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
network_info_plus:
dependency: transitive
description:
name: network_info_plus
sha256: "5bd4b86e28fed5ed4e6ac7764133c031dfb7d3f46aa2a81b46f55038aa78ecc0"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
network_info_plus_platform_interface:
dependency: transitive
description:
name: network_info_plus_platform_interface
sha256: "7e7496a8a9d8136859b8881affc613c4a21304afeb6c324bcefc4bd0aff6b94b"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
nm:
dependency: transitive
description:
name: nm
sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
objective_c:
dependency: transitive
description:
@@ -647,13 +695,6 @@ packages:
relative: true
source: path
version: "0.0.1"
playwith_game_quiz:
dependency: "direct main"
description:
path: "../../packages/games/quiz"
relative: true
source: path
version: "0.0.1"
plugin_platform_interface:
dependency: transitive
description:
@@ -987,6 +1028,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.23.4"
wifi_iot:
dependency: transitive
description:
name: wifi_iot
sha256: "0861aed0c0afd6031b4337811d31cdd181c594a8a2c73e94826ea21d2cb4707b"
url: "https://pub.dev"
source: hosted
version: "0.3.19+2"
win32:
dependency: transitive
description:
@@ -995,6 +1044,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.15.0"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852"
url: "https://pub.dev"
source: hosted
version: "1.1.5"
xdg_directories:
dependency: transitive
description:
-2
View File
@@ -33,8 +33,6 @@ dependencies:
# 로컬 패키지 추가
playwith_core:
path: ../../packages/core
playwith_game_quiz:
path: ../../packages/games/quiz
permission_handler: ^11.0.0
qr_flutter: ^4.1.0
mobile_scanner: ^5.1.0