Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
buildscript {
ext.kotlin_version = '1.9.0'
repositories {
google()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.android.tools.build:gradle:7.2.2'
}
}

plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "org.jetbrains.kotlin.android"
id "dev.flutter.flutter-gradle-plugin"
id 'com.google.gms.google-services' version '4.4.2' apply false
}

dependencies {
implementation platform('com.google.firebase:firebase-bom:33.4.0')
implementation 'com.google.firebase:firebase-analytics'

}

def localProperties = new Properties()
Expand Down
29 changes: 29 additions & 0 deletions android/app/google-services.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "480958477321",
"project_id": "routine-ade-621e0",
"storage_bucket": "routine-ade-621e0.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:480958477321:android:c2351c5c7efdd72fc3f4d8",
"android_client_info": {
"package_name": "com.example.routine_ade"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyBSwdB-8nt9YD1EoR61tUyVxQcZs2Q4r2U"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}
3 changes: 2 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.routine_ade">

<!-- 퍼미션 설정 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Expand Down
2 changes: 2 additions & 0 deletions android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip

2 changes: 1 addition & 1 deletion android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
id "org.jetbrains.kotlin.android" version "1.9.0" apply false
}

include ":app"
125 changes: 86 additions & 39 deletions lib/RoutineAdeIntro/ProfileSetting.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';

import 'package:http/http.dart' as http;
import '../routine_home/MyRoutinePage.dart';
import 'package:routine_ade/routine_user/token.dart'; // 토큰 가져오는 곳

class ProfileSetting extends StatefulWidget {
const ProfileSetting({super.key});
Expand Down Expand Up @@ -45,6 +47,69 @@ class _ProfileSettingState extends State<ProfileSetting> {
});
}

Future<void> _registerUserInfo() async {
const url = 'http://15.164.88.94/users/infos'; // API URL

// POST 요청 준비
final request = http.MultipartRequest('POST', Uri.parse(url));

// 토큰 확인 및 추가
if (token == null || token.isEmpty) {
print('Token is missing.');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('토큰이 없습니다. 다시 로그인해주세요.')),
);
return;
}

print('Current token: $token');
request.headers['Authorization'] = 'Bearer $token'; // 헤더에 토큰 추가

// 닉네임과 한 줄 소개 추가
request.fields['nickname'] = _nicknameController.text;
request.fields['intro'] = _bioController.text;

// 선택한 이미지가 있으면 파일로 추가
if (_imageFile != null) {
request.files.add(await http.MultipartFile.fromPath('image', _imageFile!.path));
}

try {
// 서버에 요청 전송
final response = await request.send();
final responseData = await http.Response.fromStream(response);

// 상태 코드가 200 또는 201인 경우에 성공 처리
if (response.statusCode == 200 || response.statusCode == 201) {
final responseBody = utf8.decode(responseData.bodyBytes);
print('User info registered successfully: $responseBody');

// MyRoutinePage로 이동
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const MyRoutinePage(),
),
);
} else {
// 실패 시 서버에서 보낸 오류 메시지 출력
final errorBody = utf8.decode(responseData.bodyBytes);
print('Failed to register user info. Status code: ${response.statusCode}');
print('Response body: $errorBody');

ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('정보 등록 실패: $errorBody')),
);
}
} catch (e) {
print('Error during registration: $e');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('정보 등록 중 오류가 발생했습니다.')),
);
}
}


@override
Widget build(BuildContext context) {
return Scaffold(
Expand All @@ -64,7 +129,6 @@ class _ProfileSettingState extends State<ProfileSetting> {
},
),
),
backgroundColor: Colors.white,
body: Stack(
children: [
Padding(
Expand All @@ -74,22 +138,21 @@ class _ProfileSettingState extends State<ProfileSetting> {
children: [
const SizedBox(height: 20),
GestureDetector(
onTap: _pickImage, // 프로필 사진을 클릭했을 때 이미지 선택 기능 실행
onTap: _pickImage,
child: Stack(
children: [
CircleAvatar(
radius: 50,
backgroundImage: _imageFile != null
? FileImage(_imageFile!)
: const AssetImage(
'assets/images/default_profile.png')
: const AssetImage('assets/images/default_profile.png')
as ImageProvider,
),
Positioned(
bottom: 0,
right: 0,
child: GestureDetector(
onTap: _pickImage, // 카메라 아이콘 클릭 시 이미지 선택 기능 실행
onTap: _pickImage,
child: const CircleAvatar(
backgroundColor: Colors.white,
radius: 16,
Expand All @@ -103,51 +166,34 @@ class _ProfileSettingState extends State<ProfileSetting> {
const SizedBox(height: 50),
const Align(
alignment: Alignment.centerLeft,
child: Text("닉네임 (필수)"),
child: Text("닉네임"),
),
const SizedBox(height: 10),
TextField(
controller: _nicknameController,
onChanged: _validateNickname,
decoration: InputDecoration(
hintText: '닉네임',
errorText: !_isNicknameValid
? _nicknameErrorMessage
: null, // 에러 메시지 표시
counterText: '', // 글자수 카운터 삭제
errorText: !_isNicknameValid ? _nicknameErrorMessage : null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: const BorderSide(
color: Colors.black, // 기본 테두리 검은색
borderSide: BorderSide(
color: _isNicknameValid ? Colors.grey : Colors.red,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: const BorderSide(
color: Colors.black, // 포커스 시 테두리 검은색
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: const BorderSide(
color: Colors.red, // 에러 상태 테두리 빨간색
width: 2.0,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: const BorderSide(
color: Colors.red, // 에러 상태에서 포커스 시 테두리 빨간색
width: 2.0,
borderSide: BorderSide(
color: _isNicknameValid ? Colors.blue : Colors.red,
),
),
),
maxLength: 10,
),
const SizedBox(height: 40),
const SizedBox(height: 20),
const Align(
alignment: Alignment.centerLeft,
child: Text("한 줄 소개 (선택)"),
child: Text("한 줄 소개"),
),
const SizedBox(height: 10),
TextField(
Expand Down Expand Up @@ -177,12 +223,13 @@ class _ProfileSettingState extends State<ProfileSetting> {
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const MyRoutinePage(),
),
);
if (_isNicknameValid) {
_registerUserInfo();
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('닉네임이 유효하지 않습니다.')),
);
}
},
child: const Text(
'완료',
Expand All @@ -195,4 +242,4 @@ class _ProfileSettingState extends State<ProfileSetting> {
),
);
}
}
}
12 changes: 11 additions & 1 deletion lib/RoutineAdeIntro/RoutineAde1.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'WebViewPage.dart';
import 'package:routine_ade/routine_user/token.dart';

void main() {
runApp(const MyApp());
Expand All @@ -25,6 +28,12 @@ class RoutineAde1 extends StatefulWidget {
}

class _RoutineAde1State extends State<RoutineAde1> {
String? _firebaseToken;
@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
Expand Down Expand Up @@ -69,7 +78,8 @@ class _RoutineAde1State extends State<RoutineAde1> {
// WebView 페이지로 이동
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const WebViewPage()),
MaterialPageRoute(
builder: (context) => const WebViewPage()),
);
},
child: Image.asset(
Expand Down
Loading