회원가입, 로그인, id pw 찾기 페이지 완료
This commit is contained in:
parent
5048ad8873
commit
0f450c884f
BIN
flutter_01.png
Normal file
BIN
flutter_01.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
@ -1,11 +1,190 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'dart:convert' show utf8;
|
||||
import 'login_page.dart';
|
||||
import 'pw_finding_page.dart';
|
||||
import 'signup_page.dart';
|
||||
|
||||
class IdFindingPage extends StatelessWidget {
|
||||
class IdFindingPage extends StatefulWidget {
|
||||
const IdFindingPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_IdFindingPageState createState() => _IdFindingPageState();
|
||||
}
|
||||
|
||||
class _IdFindingPageState extends State<IdFindingPage> {
|
||||
final TextEditingController nicknameController = TextEditingController();
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
String nicknameErrorMessage = '';
|
||||
String emailErrorMessage = '';
|
||||
String foundIdMessage = '';
|
||||
String authId = '';
|
||||
|
||||
Future<void> _findId(String nickname, String email) async {
|
||||
// 로딩 인디케이터 표시
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false, // 바깥 클릭으로 닫지 않도록 설정
|
||||
builder: (BuildContext context) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse('https://eldsoft.com:8097/user/find/id'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'nickname': nickname,
|
||||
'user_email': email,
|
||||
}),
|
||||
).timeout(const Duration(seconds: 10)); // 10초 타임아웃 설정
|
||||
|
||||
String responseBody = utf8.decode(response.bodyBytes);
|
||||
|
||||
Navigator.of(context).pop(); // 로딩 인디케이터 닫기
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
|
||||
print('ID 찾기 성공: $jsonResponse');
|
||||
|
||||
// 초기화
|
||||
setState(() {
|
||||
nicknameErrorMessage = '';
|
||||
emailErrorMessage = '';
|
||||
foundIdMessage = ''; // ID 메시지 초기화
|
||||
});
|
||||
|
||||
if (jsonResponse['response_info']['msg_title'] == '닉네임 확인') {
|
||||
setState(() {
|
||||
nicknameErrorMessage = '닉네임을 다시 확인해주세요'; // 닉네임 오류 메시지 설정
|
||||
});
|
||||
} else if (jsonResponse['response_info']['msg_title'] == '이메일 확인') {
|
||||
setState(() {
|
||||
emailErrorMessage = '이메일을 다시 확인해주세요'; // 이메일 오류 메시지 설정
|
||||
});
|
||||
} else if (jsonResponse['result'] == 'OK') {
|
||||
// ID 찾기 성공 시 처리
|
||||
setState(() {
|
||||
foundIdMessage = '당신의 ID는 ${jsonResponse['data']['user_id']} 입니다'; // ID 메시지 설정
|
||||
authId = jsonResponse['data']['auth']; // auth_id 값 저장
|
||||
});
|
||||
} else {
|
||||
_showErrorDialog(jsonResponse['response_info']['msg_title'], jsonResponse['response_info']['msg_content'], 'STAY');
|
||||
}
|
||||
} else {
|
||||
// 요청이 실패했을 때 모달 창 띄우기
|
||||
_showErrorDialog('오류', '요청이 실패했습니다. 관리자에게 문의해주세요.', 'STAY');
|
||||
}
|
||||
} catch (e) {
|
||||
Navigator.of(context).pop(); // 로딩 인디케이터 닫기
|
||||
_showErrorDialog('오류', '요청이 실패했습니다. 관리자에게 문의해주세요.', 'STAY');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _findAllId() async {
|
||||
// ID 전체 찾기 요청 처리
|
||||
print('ID 전체 찾기 요청 $authId'); // 요청 시 출력
|
||||
|
||||
// 로딩 인디케이터 표시
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false, // 바깥 클릭으로 닫지 않도록 설정
|
||||
builder: (BuildContext context) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse('https://eldsoft.com:8097/user/find/id/full'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'auth': authId, // authId 값 포함
|
||||
}),
|
||||
).timeout(const Duration(seconds: 10)); // 10초 타임아웃 설정
|
||||
|
||||
String responseBody = utf8.decode(response.bodyBytes); // UTF-8 디코딩
|
||||
|
||||
Navigator.of(context).pop(); // 로딩 인디케이터 닫기
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
|
||||
print('ID 전체 찾기 성공: $jsonResponse');
|
||||
|
||||
if (jsonResponse['result'] == 'OK') {
|
||||
// 성공 시 모달 창 띄우기
|
||||
_showSuccessDialog('이메일로 전체 ID를 발송했습니다.');
|
||||
} else {
|
||||
// 실패 시 모달 창 띄우기
|
||||
_showErrorDialog(jsonResponse['response_info']['msg_title'], jsonResponse['response_info']['msg_content'], 'STAY');
|
||||
}
|
||||
} else {
|
||||
// 요청이 실패했을 때 모달 창 띄우기
|
||||
_showErrorDialog('오류', '요청이 실패했습니다. 관리자에게 문의해주세요.', 'STAY');
|
||||
}
|
||||
} catch (e) {
|
||||
Navigator.of(context).pop(); // 로딩 인디케이터 닫기
|
||||
_showErrorDialog('오류', '요청이 실패했습니다. 관리자에게 문의해주세요.', 'STAY');
|
||||
}
|
||||
}
|
||||
|
||||
void _showErrorDialog(String title, String content, String action) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white, // 모달 배경색을 흰색으로 설정
|
||||
title: Text(title, style: const TextStyle(color: Colors.black)),
|
||||
content: Text(content, style: const TextStyle(color: Colors.black)),
|
||||
actions: <Widget>[
|
||||
Center(
|
||||
child: TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white, // 텍스트 색상
|
||||
),
|
||||
child: const Text('확인'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // 모달 닫기
|
||||
if (action == 'LOGIN') {
|
||||
Navigator.of(context).pop(); // 로그인 페이지로 이동
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _showSuccessDialog(String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('성공'),
|
||||
content: Text(message),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('확인'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // 모달 닫기
|
||||
Navigator.of(context).pop(); // 로그인 페이지로 이동
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -16,76 +195,116 @@ class IdFindingPage extends StatelessWidget {
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'ID 찾기',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '닉네임',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (foundIdMessage.isEmpty) ...[
|
||||
const Text(
|
||||
'ID 찾기',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '이메일',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
const SizedBox(height: 32),
|
||||
TextField(
|
||||
controller: nicknameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: '닉네임',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (nicknameErrorMessage.isNotEmpty) // 닉네임 오류 메시지 표시
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
nicknameErrorMessage,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
controller: emailController,
|
||||
decoration: InputDecoration(
|
||||
labelText: '이메일',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (emailErrorMessage.isNotEmpty) // 이메일 오류 메시지 표시
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
emailErrorMessage,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
_findId(nicknameController.text, emailController.text);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('ID 찾기'),
|
||||
),
|
||||
] else ...[
|
||||
// ID 찾기 성공 시 메시지 표시
|
||||
Text(
|
||||
foundIdMessage,
|
||||
style: const TextStyle(fontSize: 20, color: Colors.black),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
_findAllId(); // ID 전체 찾기 버튼 클릭 시 처리
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('ID 전체 찾기'),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text('로그인', style: TextStyle(color: Colors.black)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// ID 찾기 로직 추가
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const PwFindingPage()),
|
||||
);
|
||||
},
|
||||
child: const Text('PW 찾기', style: TextStyle(color: Colors.black)),
|
||||
),
|
||||
child: const Text('ID 찾기'),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const PwFindingPage()),
|
||||
);
|
||||
},
|
||||
child: const Text('PW 찾기', style: TextStyle(color: Colors.black)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context); // 로그인 페이지로 이동
|
||||
},
|
||||
child: const Text('로그인', style: TextStyle(color: Colors.black)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const SignUpPage()),
|
||||
);
|
||||
},
|
||||
child: const Text('회원가입', style: TextStyle(color: Colors.black)),
|
||||
),
|
||||
],
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const SignUpPage()),
|
||||
);
|
||||
},
|
||||
child: const Text('회원가입', style: TextStyle(color: Colors.black)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,4 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'dart:convert' show utf8;
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'id_finding_page.dart';
|
||||
import 'pw_finding_page.dart';
|
||||
import 'signup_page.dart';
|
||||
@ -11,7 +16,80 @@ class LoginPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _LoginPageState extends State<LoginPage> {
|
||||
bool _isChecked = false;
|
||||
final TextEditingController idController = TextEditingController();
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
bool autoLogin = false;
|
||||
String loginErrorMessage = '';
|
||||
|
||||
Future<void> _login() async {
|
||||
String id = idController.text;
|
||||
String password = passwordController.text;
|
||||
String autoLoginStatus = autoLogin ? 'Y' : 'N';
|
||||
|
||||
var bytes = utf8.encode(password);
|
||||
var digest = sha256.convert(bytes);
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse('https://eldsoft.com:8097/user/login'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'user_id': id,
|
||||
'user_pw': digest.toString(),
|
||||
}),
|
||||
).timeout(const Duration(seconds: 10));
|
||||
|
||||
String responseBody = utf8.decode(response.bodyBytes);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
|
||||
|
||||
if (jsonResponse['result'] == 'OK') {
|
||||
print('로그인 성공');
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString('auth_token', jsonResponse['auth']['token']);
|
||||
await prefs.setBool('auto_login', autoLogin);
|
||||
} else if (jsonResponse['response_info']['msg_title'] == '로그인 실패') {
|
||||
setState(() {
|
||||
loginErrorMessage = '회원정보를 다시 확인해주세요.';
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_showDialog('오류', '로그인에 실패했습니다. 관리자에게 문의해주세요.');
|
||||
}
|
||||
} catch (e) {
|
||||
_showDialog('오류', '요청이 실패했습니다. 관리자에게 문의해주세요.');
|
||||
}
|
||||
}
|
||||
|
||||
void _showDialog(String title, String content) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
title: Text(title, style: const TextStyle(color: Colors.black)),
|
||||
content: Text(content, style: const TextStyle(color: Colors.black)),
|
||||
actions: <Widget>[
|
||||
Center(
|
||||
child: TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('확인'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -36,6 +114,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
TextField(
|
||||
controller: idController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'ID',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
@ -47,6 +126,8 @@ class _LoginPageState extends State<LoginPage> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
controller: passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'PW',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
@ -55,15 +136,23 @@ class _LoginPageState extends State<LoginPage> {
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
obscureText: true,
|
||||
),
|
||||
if (loginErrorMessage.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
loginErrorMessage,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _isChecked,
|
||||
onChanged: (value) {
|
||||
value: autoLogin,
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
_isChecked = value ?? false;
|
||||
autoLogin = value ?? false;
|
||||
});
|
||||
},
|
||||
),
|
||||
@ -72,9 +161,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// 로그인 로직 추가
|
||||
},
|
||||
onPressed: _login,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
|
@ -1,11 +1,118 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'dart:convert' show utf8;
|
||||
import 'login_page.dart'; // 로그인 페이지 임포트 추가
|
||||
import 'signup_page.dart'; // 회원가입 페이지 임포트 추가
|
||||
import 'id_finding_page.dart'; // ID 찾기 페이지 임포트 추가
|
||||
|
||||
class PwFindingPage extends StatelessWidget {
|
||||
class PwFindingPage extends StatefulWidget {
|
||||
const PwFindingPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PwFindingPageState createState() => _PwFindingPageState();
|
||||
}
|
||||
|
||||
class _PwFindingPageState extends State<PwFindingPage> {
|
||||
final TextEditingController idController = TextEditingController(); // ID 입력 컨트롤러
|
||||
final TextEditingController emailController = TextEditingController(); // 이메일 입력 컨트롤러
|
||||
String emailErrorMessage = ''; // 이메일 오류 메시지
|
||||
String idErrorMessage = ''; // ID 오류 메시지
|
||||
|
||||
Future<void> _findPassword(String id, String email) async {
|
||||
// PW 찾기 요청 처리
|
||||
print('PW 찾기 요청: ID: $id, 이메일: $email'); // 요청 시 출력
|
||||
|
||||
// 로딩 인디케이터 표시
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false, // 바깥 클릭으로 닫지 않도록 설정
|
||||
builder: (BuildContext context) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse('https://eldsoft.com:8097/user/find/password'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'user_id': id,
|
||||
'user_email': email,
|
||||
}),
|
||||
).timeout(const Duration(seconds: 10)); // 10초 타임아웃 설정
|
||||
|
||||
String responseBody = utf8.decode(response.bodyBytes); // UTF-8 디코딩
|
||||
|
||||
Navigator.of(context).pop(); // 로딩 인디케이터 닫기
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
|
||||
print('PW 찾기 성공: $jsonResponse');
|
||||
|
||||
// 추기화
|
||||
setState(() {
|
||||
emailErrorMessage = '';
|
||||
idErrorMessage = '';
|
||||
});
|
||||
|
||||
if (jsonResponse['response_info']['msg_title'] == '아이디 확인') {
|
||||
setState(() {
|
||||
idErrorMessage = '아이디를 다시 확인해주세요'; // ID 오류 메시지 설정
|
||||
});
|
||||
} else if (jsonResponse['response_info']['msg_title'] == '이메일 확인') {
|
||||
setState(() {
|
||||
emailErrorMessage = '이메일을 다시 확인해주세요'; // 이메일 오류 메시지 설정
|
||||
});
|
||||
} else if (jsonResponse['result'] == 'OK') {
|
||||
// 성공 시 모달 창 띄우기
|
||||
_showDialog('비밀번호 찾기 안내', '임시 비밀번호가 입력하신 이메일로 발송되었습니다.', 'LOGIN');
|
||||
} else {
|
||||
// 실패 시 모달 창 띄우기
|
||||
_showDialog(jsonResponse['response_info']['msg_title'], jsonResponse['response_info']['msg_content'], 'STAY');
|
||||
}
|
||||
} else {
|
||||
// 요청이 실패했을 때 모달 창 띄우기
|
||||
_showDialog('오류', '요청이 실패했습니다. 관리자에게 문의해주세요.', 'STAY');
|
||||
}
|
||||
} catch (e) {
|
||||
Navigator.of(context).pop(); // 로딩 인디케이터 닫기
|
||||
_showDialog('오류', '요청이 실패했습니다. 관리자에게 문의해주세요.', 'STAY');
|
||||
}
|
||||
}
|
||||
|
||||
void _showDialog(String title, String content, String action) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white, // 모달 배경색을 흰색으로 설정
|
||||
title: Text(title, style: const TextStyle(color: Colors.black)),
|
||||
content: Text(content, style: const TextStyle(color: Colors.black)),
|
||||
actions: <Widget>[
|
||||
Center(
|
||||
child: TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white, // 텍스트 색상
|
||||
),
|
||||
child: const Text('확인'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // 모달 닫기
|
||||
if (action == 'LOGIN') {
|
||||
Navigator.of(context).pop(); // 로그인 페이지로 이동
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -29,6 +136,7 @@ class PwFindingPage extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
TextField(
|
||||
controller: idController, // ID 입력 필드
|
||||
decoration: InputDecoration(
|
||||
labelText: 'ID',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
@ -38,8 +146,17 @@ class PwFindingPage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (idErrorMessage.isNotEmpty) // ID 오류 메시지 표시
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
idErrorMessage,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
controller: emailController, // 이메일 입력 필드
|
||||
decoration: InputDecoration(
|
||||
labelText: '이메일',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
@ -49,10 +166,18 @@ class PwFindingPage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (emailErrorMessage.isNotEmpty) // 이메일 오류 메시지 표시
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
emailErrorMessage,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// PW 찾기 로직 추가
|
||||
_findPassword(idController.text, emailController.text); // PW 찾기 요청
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
|
@ -1,5 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http; // http 패키지 임포트
|
||||
import 'dart:convert'; // JSON 변환을 위해 임포트
|
||||
import 'login_page.dart'; // 로그인 페이지 임포트 추가
|
||||
import 'dart:convert' show utf8; // UTF-8 디코딩을 위해 임포트
|
||||
import 'package:crypto/crypto.dart'; // crypto 패키지 임포트
|
||||
|
||||
class SignUpPage extends StatefulWidget {
|
||||
const SignUpPage({Key? key}) : super(key: key);
|
||||
@ -9,27 +13,170 @@ class SignUpPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SignUpPageState extends State<SignUpPage> {
|
||||
// 상태 변수
|
||||
bool _isAgreed = false; // 개인정보 수집 동의 체크박스 상태
|
||||
String _username = ''; // 아이디 입력값
|
||||
String? _usernameError; // 아이디 오류 메시지
|
||||
String _username = '', _password = '', _confirmPassword = '', _nickname = '', _email = '';
|
||||
String _department = '', _introduceMyself = ''; // 소속 및 자기소개
|
||||
String? _usernameError, _passwordError, _confirmPasswordError, _nicknameError, _emailError;
|
||||
|
||||
// 아이디 패턴 검증
|
||||
bool _isUsernameValid(String username) {
|
||||
final RegExp regex = RegExp(r'^(?![0-9])[A-Za-z0-9]{6,20}$');
|
||||
return regex.hasMatch(username);
|
||||
}
|
||||
// 유효성 검사
|
||||
bool _isUsernameValid(String username) => RegExp(r'^(?![0-9])[A-Za-z0-9]{6,20}$').hasMatch(username);
|
||||
bool _isPasswordValidPattern(String password) => RegExp(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,20}$').hasMatch(password);
|
||||
bool _isEmailValid(String email) => RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(email);
|
||||
bool _isNicknameValid(String nickname) => RegExp(r'^[A-Za-z가-힣0-9]{2,20}$').hasMatch(nickname);
|
||||
|
||||
void _validateUsername(String value) {
|
||||
// 입력값 검증
|
||||
void _validateInput(String label) {
|
||||
setState(() {
|
||||
_username = value;
|
||||
if (_isUsernameValid(value)) {
|
||||
_usernameError = null; // 유효한 경우 오류 메시지 제거
|
||||
} else {
|
||||
_usernameError = '* 아이디는 6~20자 영문 대소문자와 숫자 조합이어야 하며, 숫자로 시작할 수 없습니다.';
|
||||
if (label == '아이디') {
|
||||
_usernameError = _isUsernameValid(_username) ? null : '아이디는 6~20자 영문 대소문자와 숫자 조합이어야 하며, 숫자로 시작할 수 없습니다.';
|
||||
} else if (label == '비밀번호') {
|
||||
_passwordError = _isPasswordValidPattern(_password) ? null : '비밀번호는 8~20자 영문과 숫자가 반드시 포함된 조합이어야 합니다.';
|
||||
} else if (label == '비밀번호 확인') {
|
||||
_confirmPasswordError = _password == _confirmPassword ? null : '비밀번호가 일치하지 않습니다.';
|
||||
} else if (label == '닉네임') {
|
||||
_nicknameError = _isNicknameValid(_nickname) ? null : '* 닉네임은 2~20자 영문, 한글, 숫자만 사용할 수 있습니다.';
|
||||
} else if (label == '이메일') {
|
||||
_emailError = _isEmailValid(_email) ? null : (_email.isNotEmpty ? '올바른 이메일 형식을 입력해주세요.' : null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 회원가입 요청
|
||||
Future<void> _signUp() async {
|
||||
final url = 'https://eldsoft.com:8097/user/signup';
|
||||
|
||||
// 체크박스 상태에 따라 mandatory_terms_yn 값 설정
|
||||
final mandatoryTermsYn = _isAgreed ? 'Y' : 'N';
|
||||
|
||||
// 비밀번호를 SHA-256으로 해싱
|
||||
final hashedPassword = _hashPassword(_password);
|
||||
|
||||
final body = {
|
||||
"user_id": _username,
|
||||
"user_pw": hashedPassword, // 해싱된 비밀번호 사용
|
||||
"nickname": _nickname,
|
||||
"user_email": _email,
|
||||
"department": _department,
|
||||
"introduce_myself": _introduceMyself,
|
||||
"mandatory_terms_yn": mandatoryTermsYn // 체크박스 상태에 따라 값 설정
|
||||
};
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(url),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode(body),
|
||||
);
|
||||
|
||||
// 응답 body를 UTF-8로 디코딩하여 변수에 저장
|
||||
final resBody = json.decode(utf8.decode(response.bodyBytes));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// result가 OK이어야만 성공여부 판단 가능
|
||||
print(resBody);
|
||||
if (resBody['result'] == 'OK') {
|
||||
if (resBody['response_info']['msg_type'] == 'OK') {
|
||||
_showDialog('회원가입 성공', '회원가입이 완료되었습니다.');
|
||||
} else {
|
||||
_showDialog('회원가입 실패', '${resBody['response_info']['msg_content']}');
|
||||
}
|
||||
} else {
|
||||
_showDialog('회원가입 실패', '${resBody['response_info']['msg_content']}');
|
||||
}
|
||||
} else {
|
||||
final errorData = json.decode(response.body);
|
||||
_showDialog('회원가입 실패', errorData['message'] ?? '회원가입 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
_showDialog('네트워크 오류', '네트워크 오류: $error');
|
||||
}
|
||||
}
|
||||
|
||||
// 모밀번호 해싱 함수
|
||||
String _hashPassword(String password) {
|
||||
final bytes = utf8.encode(password); // 비밀번호를 바이트로 변환
|
||||
final digest = sha256.convert(bytes); // SHA-256 해싱
|
||||
return digest.toString(); // 해싱된 비밀번호를 문자열로 반환
|
||||
}
|
||||
|
||||
// 모달 창 표시
|
||||
void _showDialog(String title, String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white, // 배경색
|
||||
title: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black, // 제목 색상
|
||||
),
|
||||
),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min, // 내용 크기에 맞게 조정
|
||||
children: [
|
||||
Text(
|
||||
message,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.black, // 내용 색상
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20), // 여백 추가
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // 모달 닫기
|
||||
if (title == '회원가입 성공') {
|
||||
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => LoginPage())); // 로그인 페이지로 이동
|
||||
}
|
||||
// '회원가입 성공'이 아닐 경우 아무 동작도 하지 않음
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.white, // 버튼 텍스트 색상
|
||||
backgroundColor: Colors.black, // 버튼 배경색
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), // 버튼 패딩
|
||||
),
|
||||
child: const Text('확인'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// 입력 필드 위젯
|
||||
Widget _buildTextField(String label, Function(String) onChanged, {bool obscureText = false, String? errorText}) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextField(
|
||||
onChanged: (value) {
|
||||
onChanged(value);
|
||||
_validateInput(label); // label에 따라 유효성 검사 수행
|
||||
},
|
||||
obscureText: obscureText,
|
||||
decoration: InputDecoration(
|
||||
labelText: label,
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(borderSide: const BorderSide(color: Colors.black, width: 2.0)),
|
||||
errorStyle: const TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
),
|
||||
if (errorText != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(errorText, style: const TextStyle(color: Colors.red, fontSize: 12)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -39,136 +186,36 @@ class _SignUpPageState extends State<SignUpPage> {
|
||||
backgroundColor: Colors.black,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.chevron_left, color: Colors.white),
|
||||
onPressed: () {
|
||||
Navigator.pop(context); // 로그인 페이지로 이동
|
||||
},
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: SingleChildScrollView( // 스크롤 가능하게 설정
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'회원가입',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const Text('회원가입', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black)),
|
||||
const SizedBox(height: 32),
|
||||
TextField(
|
||||
onChanged: _validateUsername, // 아이디 입력 시 검증
|
||||
decoration: InputDecoration(
|
||||
labelText: '아이디',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_usernameError != null) // 오류 메시지 표시
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
_usernameError!,
|
||||
style: const TextStyle(color: Colors.red, fontSize: 12), // 폰트 크기 줄임
|
||||
),
|
||||
),
|
||||
_buildTextField('아이디', (value) => _username = value, errorText: _usernameError),
|
||||
_buildTextField('비밀번호', (value) => _password = value, obscureText: true, errorText: _passwordError),
|
||||
_buildTextField('비밀번호 확인', (value) => _confirmPassword = value, obscureText: true, errorText: _confirmPasswordError),
|
||||
_buildTextField('닉네임', (value) => _nickname = value, errorText: _nicknameError),
|
||||
_buildTextField('이메일', (value) => _email = value, errorText: _emailError),
|
||||
_buildTextField('소속(선택사항)', (value) => _department = value),
|
||||
_buildTextField('자기소개(선택사항)', (value) => _introduceMyself = value),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '비밀번호',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
obscureText: true,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '비밀번호 확인',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
obscureText: true,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '닉네임',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '이메일',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '소속',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '자기소개',
|
||||
labelStyle: const TextStyle(color: Colors.black),
|
||||
border: OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.black, width: 2.0),
|
||||
),
|
||||
),
|
||||
maxLines: 3, // 여러 줄 입력 가능
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'개인정보 수집 및 이용 동의서',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const Text('개인정보 수집 및 이용 동의서', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black)),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 200, // 스크롤 가능한 영역의 높이 설정
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.black.withOpacity(0.5)), // 부드러운 테두리
|
||||
borderRadius: BorderRadius.circular(8), // 모서리 둥글게
|
||||
),
|
||||
child: Scrollbar( // 스크롤바 추가
|
||||
thickness: 5, // 스크롤바 두께
|
||||
radius: Radius.circular(5), // 스크롤바 둥글게
|
||||
height: 200,
|
||||
decoration: BoxDecoration(border: Border.all(color: Colors.black.withOpacity(0.5)), borderRadius: BorderRadius.circular(8)),
|
||||
child: Scrollbar(
|
||||
thickness: 5,
|
||||
radius: const Radius.circular(5),
|
||||
child: SingleChildScrollView(
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15.0), // 여백 추가
|
||||
padding: EdgeInsets.all(15.0),
|
||||
child: Text(
|
||||
'올스코어(이하 "회사"라 합니다)는 이용자의 개인정보를 중요시하며, '
|
||||
'「개인정보 보호법」 등 관련 법령을 준수하고 있습니다. '
|
||||
@ -183,7 +230,7 @@ class _SignUpPageState extends State<SignUpPage> {
|
||||
'부정 이용 방지 및 비인가 사용 방지\n'
|
||||
'서비스 이용에 따른 문의 사항 처리\n'
|
||||
'서비스 제공\n'
|
||||
'게임 방 생성 및 참여 등 기본 서비스 제공\n'
|
||||
'게임 생성 및 참여 등 기본 서비스 제공\n'
|
||||
'통계 및 순위 제공 등 부가 서비스 제공\n'
|
||||
'고객 지원 및 공지사항 전달\n'
|
||||
'서비스 관련 중요한 공지사항 전달\n'
|
||||
@ -237,10 +284,7 @@ class _SignUpPageState extends State<SignUpPage> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// 회원가입 로직 추가
|
||||
Navigator.pop(context); // 로그인 페이지로 이동
|
||||
},
|
||||
onPressed: _signUp, // 회원가입 로직 추가
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
|
@ -5,6 +5,8 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import shared_preferences_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
}
|
||||
|
167
pubspec.lock
167
pubspec.lock
@ -41,6 +41,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.0"
|
||||
crypto:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: crypto
|
||||
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -57,6 +65,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -75,6 +99,27 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
http:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: http
|
||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -139,6 +184,102 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.6"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
shared_preferences:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.4"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -192,6 +333,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.3"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -208,6 +357,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.0"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
sdks:
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
flutter: ">=3.18.0-18.0.pre.54"
|
||||
flutter: ">=3.24.0"
|
||||
|
@ -38,6 +38,9 @@ dependencies:
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
http: ^1.2.2
|
||||
crypto: ^3.0.1
|
||||
shared_preferences: ^2.0.6
|
||||
|
||||
# The "flutter_lints" package below contains a set of recommended lints to
|
||||
# encourage good coding practices. The lint set provided by the package is
|
||||
|
Loading…
Reference in New Issue
Block a user