반려동물 등록 페이지 ui / 반응형

This commit is contained in:
youngbeom 2026-01-23 15:29:20 +09:00
parent 683f04742a
commit c36fe45df2
31 changed files with 2419 additions and 552 deletions

View File

@ -0,0 +1,12 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_12643)">
<circle cx="10" cy="10" r="10" fill="#FF7500"/>
<path d="M11.0585 15.1849H8.92441C6.91251 15.1849 5.90629 15.1849 5.28154 14.5596C4.65678 13.9343 4.65625 12.9286 4.65625 10.9167V9.84969C4.65625 7.83779 4.65625 6.83157 5.28154 6.20682C5.90682 5.58206 6.91251 5.58153 8.92441 5.58153H11.0585C13.0704 5.58153 14.0766 5.58153 14.7014 6.20682C15.3261 6.8321 15.3267 7.83779 15.3267 9.84969V10.9167C15.3267 12.9286 15.3267 13.9349 14.7014 14.5596C14.353 14.9085 13.8862 15.0627 13.1926 15.1305M7.32385 5.58153V4.78125M12.6591 5.58153V4.78125M15.0599 8.24913H9.32455M4.65625 8.24913H6.72364" stroke="white" stroke-width="1.3" stroke-linecap="round"/>
<path d="M13.1913 12.5114C13.1913 12.6529 13.1351 12.7886 13.035 12.8886C12.935 12.9887 12.7993 13.0449 12.6578 13.0449C12.5163 13.0449 12.3806 12.9887 12.2805 12.8886C12.1805 12.7886 12.1243 12.6529 12.1243 12.5114C12.1243 12.3699 12.1805 12.2341 12.2805 12.1341C12.3806 12.034 12.5163 11.9778 12.6578 11.9778C12.7993 11.9778 12.935 12.034 13.035 12.1341C13.1351 12.2341 13.1913 12.3699 13.1913 12.5114ZM13.1913 10.3773C13.1913 10.5188 13.1351 10.6545 13.035 10.7545C12.935 10.8546 12.7993 10.9108 12.6578 10.9108C12.5163 10.9108 12.3806 10.8546 12.2805 10.7545C12.1805 10.6545 12.1243 10.5188 12.1243 10.3773C12.1243 10.2358 12.1805 10.1001 12.2805 10C12.3806 9.89996 12.5163 9.84375 12.6578 9.84375C12.7993 9.84375 12.935 9.89996 13.035 10C13.1351 10.1001 13.1913 10.2358 13.1913 10.3773ZM10.5237 12.5114C10.5237 12.6529 10.4675 12.7886 10.3674 12.8886C10.2674 12.9887 10.1317 13.0449 9.99018 13.0449C9.84869 13.0449 9.71298 12.9887 9.61293 12.8886C9.51287 12.7886 9.45666 12.6529 9.45666 12.5114C9.45666 12.3699 9.51287 12.2341 9.61293 12.1341C9.71298 12.034 9.84869 11.9778 9.99018 11.9778C10.1317 11.9778 10.2674 12.034 10.3674 12.1341C10.4675 12.2341 10.5237 12.3699 10.5237 12.5114ZM10.5237 10.3773C10.5237 10.5188 10.4675 10.6545 10.3674 10.7545C10.2674 10.8546 10.1317 10.9108 9.99018 10.9108C9.84869 10.9108 9.71298 10.8546 9.61293 10.7545C9.51287 10.6545 9.45666 10.5188 9.45666 10.3773C9.45666 10.2358 9.51287 10.1001 9.61293 10C9.71298 9.89996 9.84869 9.84375 9.99018 9.84375C10.1317 9.84375 10.2674 9.89996 10.3674 10C10.4675 10.1001 10.5237 10.2358 10.5237 10.3773ZM7.8561 12.5114C7.8561 12.6529 7.79989 12.7886 7.69984 12.8886C7.59978 12.9887 7.46408 13.0449 7.32258 13.0449C7.18108 13.0449 7.04538 12.9887 6.94533 12.8886C6.84527 12.7886 6.78906 12.6529 6.78906 12.5114C6.78906 12.3699 6.84527 12.2341 6.94533 12.1341C7.04538 12.034 7.18108 11.9778 7.32258 11.9778C7.46408 11.9778 7.59978 12.034 7.69984 12.1341C7.79989 12.2341 7.8561 12.3699 7.8561 12.5114ZM7.8561 10.3773C7.8561 10.5188 7.79989 10.6545 7.69984 10.7545C7.59978 10.8546 7.46408 10.9108 7.32258 10.9108C7.18108 10.9108 7.04538 10.8546 6.94533 10.7545C6.84527 10.6545 6.78906 10.5188 6.78906 10.3773C6.78906 10.2358 6.84527 10.1001 6.94533 10C7.04538 9.89996 7.18108 9.84375 7.32258 9.84375C7.46408 9.84375 7.59978 9.89996 7.69984 10C7.79989 10.1001 7.8561 10.2358 7.8561 10.3773Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_1_12643">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.70833 9.16667C2.70833 7.45381 3.38876 5.81111 4.59994 4.59994C5.81111 3.38876 7.45381 2.70833 9.16667 2.70833C10.8795 2.70833 12.5222 3.38876 13.7334 4.59994C14.9446 5.81111 15.625 7.45381 15.625 9.16667C15.625 10.8795 14.9446 12.5222 13.7334 13.7334C12.5222 14.9446 10.8795 15.625 9.16667 15.625C7.45381 15.625 5.81111 14.9446 4.59994 13.7334C3.38876 12.5222 2.70833 10.8795 2.70833 9.16667ZM9.16667 0.625C4.45 0.625 0.625 4.45 0.625 9.16667C0.625 13.8833 4.45 17.7083 9.16667 17.7083C10.8854 17.7083 12.4852 17.2008 13.8251 16.3273C14.1779 16.0973 14.6488 16.1222 14.9466 16.42L17.0074 18.4807C17.3328 18.8062 17.8605 18.8062 18.1859 18.4807L18.4807 18.1859C18.8062 17.8605 18.8062 17.3328 18.4807 17.0074L16.4205 14.9471C16.1225 14.6491 16.0978 14.1778 16.3281 13.8248C17.2286 12.4439 17.7112 10.8258 17.7083 9.16667C17.7083 4.45 13.8842 0.625 9.16667 0.625Z" fill="#1F1F1F"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,10 @@
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_46_845)">
<path d="M8.52082 5.16501C9.00013 5.16501 9.45981 4.9746 9.79873 4.63568C10.1377 4.29676 10.3281 3.83708 10.3281 3.35777C10.3281 2.91701 10.2412 2.48057 10.0726 2.07337C9.90391 1.66616 9.65668 1.29616 9.34502 0.984503C9.03336 0.672841 8.66336 0.425618 8.25616 0.256948C7.84895 0.0882781 7.41251 0.00146484 6.97176 0.00146484C6.49245 0.00146484 6.03277 0.19187 5.69385 0.530793C5.35492 0.869716 5.16452 1.32939 5.16452 1.8087C5.16452 1.32939 4.97411 0.869716 4.63519 0.530793C4.29627 0.19187 3.83659 0.00146484 3.35728 0.00146484C2.46713 0.00146484 1.61344 0.355074 0.984015 0.984503C0.354586 1.61393 0.000976563 2.46762 0.000976562 3.35777C0.000976563 3.83708 0.191382 4.29676 0.530305 4.63568C0.869228 4.9746 1.32891 5.16501 1.80822 5.16501C1.32891 5.16501 0.869228 5.35541 0.530305 5.69433C0.191382 6.03326 0.000976563 6.49294 0.000976562 6.97225C0.000976562 7.413 0.0877898 7.84944 0.25646 8.25665C0.42513 8.66385 0.672353 9.03385 0.984015 9.34551C1.61344 9.97494 2.46713 10.3285 3.35728 10.3285C3.83659 10.3285 4.29627 10.1381 4.63519 9.79922C4.97411 9.4603 5.16452 9.00062 5.16452 8.52131C5.16452 9.00062 5.35492 9.4603 5.69385 9.79922C6.03277 10.1381 6.49245 10.3285 6.97176 10.3285C7.41251 10.3285 7.84895 10.2417 8.25616 10.0731C8.66336 9.9044 9.03336 9.65717 9.34502 9.34551C9.65668 9.03385 9.90391 8.66385 10.0726 8.25665C10.2412 7.84944 10.3281 7.413 10.3281 6.97225C10.3281 6.49294 10.1377 6.03326 9.79873 5.69433C9.45981 5.35541 9.00013 5.16501 8.52082 5.16501Z" fill="#6BE500"/>
</g>
<defs>
<clipPath id="clip0_46_845">
<rect width="10.33" height="10.33" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,7 @@
<svg width="29" height="35" viewBox="0 0 29 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.46191 0.957031C8.04783 0.957123 9.33301 2.24316 9.33301 3.8291C9.33292 5.41496 8.04778 6.7001 6.46191 6.7002C4.87597 6.7002 3.58994 5.41502 3.58984 3.8291C3.58984 2.24311 4.87592 0.957031 6.46191 0.957031Z" fill="#C8C8C8" stroke="#C8C8C8" stroke-width="1.91447"/>
<path d="M21.7871 0.957031C23.373 0.957123 24.6582 2.24316 24.6582 3.8291C24.6581 5.41496 23.373 6.7001 21.7871 6.7002C20.2012 6.7002 18.9151 5.41502 18.915 3.8291C18.915 2.24311 20.2011 0.957031 21.7871 0.957031Z" fill="#C8C8C8" stroke="#C8C8C8" stroke-width="1.91447"/>
<path d="M14.1196 21.0566C14.1196 24.2289 15.0768 31.5862 8.37621 31.5862C6.85297 31.5862 5.39211 30.9811 4.31501 29.904C3.23792 28.8269 2.63281 27.366 2.63281 25.8428" stroke="#C8C8C8" stroke-width="5.26478" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.1801 21.0566C14.1801 24.2289 13.2229 31.5862 19.9235 31.5862C21.4467 31.5862 22.9076 30.9811 23.9847 29.904C25.0618 28.8269 25.6669 27.366 25.6669 25.8428" stroke="#C8C8C8" stroke-width="5.26478" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17.9401 20.5747C17.9401 21.8957 14.1112 23.925 14.1112 23.925C14.1112 23.925 10.2822 21.8957 10.2822 20.5747C10.2822 19.2537 11.2395 18.1816 14.1112 18.1816C16.9829 18.1816 17.9401 19.2537 17.9401 20.5747Z" fill="white" stroke="#C8C8C8" stroke-width="5.26478" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/assets/img/badicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

BIN
app/assets/img/goodicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

BIN
app/assets/img/profile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

View File

@ -1,3 +1,4 @@
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:firebase_core/firebase_core.dart';
@ -35,10 +36,17 @@ class RupApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
home: const SplashScreen(),
return ScreenUtilInit(
designSize: const Size(375, 812), // set
minTextAdapt: true,
splitScreenMode: true,
builder: (context, child) {
return MaterialApp(
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
home: const SplashScreen(),
);
},
);
}
}

View File

@ -1,4 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import 'pet_registration_screen.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@ -6,17 +8,64 @@ class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: const SafeArea(
child: Center(
child: Text(
'로그인 성공!\n여기는 메인 홈 화면입니다.',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
fontSize: 18,
backgroundColor: Colors.white,
body: SafeArea(
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 20.h),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(
8.r,
), // Optional: Add radius
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const PetRegistrationScreen(),
),
);
},
child: Row(
mainAxisSize: MainAxisSize.min, // Wrap content only
children: [
Image.asset(
'assets/img/profile.png',
width: 40.w,
height: 40.h,
),
SizedBox(width: 10.w),
Text(
'반려동물 등록 +',
style: TextStyle(
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
fontSize: 15.sp,
letterSpacing: 0.45.sp,
color: const Color(0xFF1f1f1f),
),
),
],
),
),
),
),
),
Expanded(
child: Center(
child: Text(
'로그인 성공!\n여기는 메인 홈 화면입니다.',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
fontSize: 18.sp,
),
),
),
),
],
),
),
);

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import 'main_screen.dart';
class IdentityVerificationScreen extends StatelessWidget {
@ -12,13 +13,13 @@ class IdentityVerificationScreen extends StatelessWidget {
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black, size: 20),
icon: Icon(Icons.arrow_back_ios, color: Colors.black, size: 20.w),
onPressed: () => Navigator.pop(context),
),
title: const Text(
title: Text(
'본인 인증',
style: TextStyle(
fontSize: 15,
fontSize: 15.sp,
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
color: Colors.black,
@ -27,52 +28,52 @@ class IdentityVerificationScreen extends StatelessWidget {
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(20.0),
padding: EdgeInsets.all(20.0.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 20),
const Text(
SizedBox(height: 20.h),
Text(
'더 안전한 서비스 이용을 위해\n본인 인증을 진행해 주세요.',
style: TextStyle(
fontSize: 20,
fontSize: 20.sp,
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
const SizedBox(height: 40),
SizedBox(height: 40.h),
// UI (Placeholder)
Container(
padding: const EdgeInsets.all(20),
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(10),
borderRadius: BorderRadius.circular(10.r),
border: Border.all(color: Colors.grey[300]!),
),
child: Column(
children: [
const Icon(
Icon(
Icons.shield_outlined,
size: 50,
color: Color(0xFFFF7500),
size: 50.w,
color: const Color(0xFFFF7500),
),
const SizedBox(height: 10),
const Text(
SizedBox(height: 10.h),
Text(
'PASS / 문자 인증',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 16,
fontSize: 16.sp,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 10),
const Text(
SizedBox(height: 10.h),
Text(
'(현재 UI만 구현된 상태입니다)',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 12,
fontSize: 12.sp,
color: Colors.grey,
),
),
@ -92,22 +93,22 @@ class IdentityVerificationScreen extends StatelessWidget {
(route) => false,
);
},
child: const Text(
child: Text(
'다음에 하기 (건너뛰기)',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 14,
fontSize: 14.sp,
fontWeight: FontWeight.w500,
color: Colors.grey,
decoration: TextDecoration.underline,
),
),
),
const SizedBox(height: 10),
SizedBox(height: 10.h),
// ( X)
SizedBox(
height: 50,
height: 50.h,
child: ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
@ -118,21 +119,21 @@ class IdentityVerificationScreen extends StatelessWidget {
backgroundColor: const Color(0xFFFF7500),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(8.r),
),
),
child: const Text(
child: Text(
'인증하기',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 16,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
const SizedBox(height: 10),
SizedBox(height: 10.h),
],
),
),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import '../services/auth_service.dart';
import 'main_screen.dart';
import 'terms_agreement_screen.dart'; // Import TermsAgreementScreen
@ -71,17 +72,17 @@ class _LoginScreenState extends State<LoginScreen> {
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(
icon: Icon(
Icons.arrow_back_ios,
color: Colors.black,
size: 20,
size: 16.w, // Responsive size
),
onPressed: () => Navigator.pop(context),
),
title: const Text(
'로그인',
title: Text(
'간편 로그인',
style: TextStyle(
fontSize: 15,
fontSize: 15.sp, // Responsive font size
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
color: Colors.black,
@ -90,20 +91,28 @@ class _LoginScreenState extends State<LoginScreen> {
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 240),
padding: EdgeInsets.fromLTRB(
20.w,
0,
20.w,
240.h,
), // Responsive padding
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20),
SizedBox(height: 20.h), // Responsive height
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset('assets/img/foot.png', width: 30),
SizedBox(width: 10),
Image.asset(
'assets/img/foot.png',
width: 30.w,
), // Responsive width
SizedBox(width: 10.w), // Responsive width
Text(
'로그인',
'간편 로그인',
style: TextStyle(
fontSize: 24,
fontSize: 24.sp, // Responsive font size
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
color: Colors.black,
@ -111,29 +120,29 @@ class _LoginScreenState extends State<LoginScreen> {
),
],
),
SizedBox(height: 10),
SizedBox(height: 10.h),
Text(
'RUP에 어서오세요!\n지금 로그인하고 다양한 서비스를 이용해보세요.',
'똑똑한 반려생활을 위한 첫걸음,\nRUP에 오신것을 환영해요!',
style: TextStyle(
fontSize: 14,
fontSize: 14.sp,
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
color: Colors.black,
),
textAlign: TextAlign.start,
),
Spacer(),
const Spacer(),
Align(
alignment: Alignment.centerRight,
child: Image.asset('assets/img/cat.png', height: 150),
child: Image.asset('assets/img/cat.png', height: 150.h),
),
SizedBox(height: 10),
SizedBox(height: 10.h),
],
),
),
bottomSheet: Container(
color: Colors.white,
padding: const EdgeInsets.fromLTRB(20, 20, 20, 40),
padding: EdgeInsets.fromLTRB(20.w, 20.h, 20.w, 40.h),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
@ -144,31 +153,31 @@ class _LoginScreenState extends State<LoginScreen> {
textColor: Colors.white,
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
fontSize: 15,
fontSize: 15.sp,
backgroundColor: const Color(0xFF00D03F),
onPressed: () {},
iconPath: 'assets/icons/navericon.svg',
),
const SizedBox(height: 15),
SizedBox(height: 15.h),
// Kakao Login Button
_SocialLoginButton(
text: '카카오 로그인',
textColor: const Color(0xFF212121),
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
fontSize: 15,
fontSize: 15.sp,
backgroundColor: const Color(0xFFFAE100),
onPressed: () {},
iconPath: 'assets/icons/kakaoicon.svg',
),
const SizedBox(height: 15),
SizedBox(height: 15.h),
// Google Login Button
_SocialLoginButton(
text: '구글 로그인',
textColor: const Color(0xFF17191A),
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
fontSize: 15,
fontSize: 15.sp,
backgroundColor: Colors.white,
onPressed: _handleGoogleLogin,
iconPath: 'assets/icons/googleicon.svg',
@ -180,7 +189,7 @@ class _LoginScreenState extends State<LoginScreen> {
),
if (_isLoading)
Container(
color: Colors.black.withOpacity(0.5),
color: Colors.black.withValues(alpha: 0.5),
child: const Center(child: CircularProgressIndicator()),
),
],
@ -208,13 +217,13 @@ class _SocialLoginButton extends StatelessWidget {
this.isBordered = false,
this.fontFamily = 'SCDream',
this.fontWeight = FontWeight.w500,
this.fontSize = 16,
required this.fontSize, // Make required to ensure passed value is used
});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 50,
height: 50.h,
child: ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
@ -226,14 +235,14 @@ class _SocialLoginButton extends StatelessWidget {
? BorderSide(color: Colors.grey[300]!)
: BorderSide.none,
),
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: EdgeInsets.symmetric(horizontal: 20.w),
),
child: Row(
children: [
SvgPicture.asset(
iconPath,
width: 24,
height: 24,
width: 24.w,
height: 24.h,
fit: BoxFit.contain,
),
Expanded(
@ -247,7 +256,7 @@ class _SocialLoginButton extends StatelessWidget {
textAlign: TextAlign.center,
),
),
const SizedBox(width: 24),
SizedBox(width: 24.w),
],
),
),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import 'home_screen.dart';
import 'reservation_screen.dart';
import 'mungnyangz_screen.dart';
@ -37,8 +38,8 @@ class _MainScreenState extends State<MainScreen> {
Widget _buildSvgIcon(String assetName, int index) {
return SvgPicture.asset(
assetName,
width: 24,
height: 24,
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(
_selectedIndex == index
? AppColors.highlight
@ -52,66 +53,82 @@ class _MainScreenState extends State<MainScreen> {
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(index: _selectedIndex, children: _screens),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped,
type: BottomNavigationBarType.fixed,
selectedItemColor: AppColors.highlight,
unselectedItemColor: AppColors.inactive,
selectedLabelStyle: TextStyle(
fontFamily: 'SCDream',
fontSize: 12,
fontWeight: FontWeight.w500, // Medium
bottomNavigationBar: Container(
padding: EdgeInsets.symmetric(vertical: 10.h),
decoration: const BoxDecoration(
color: Colors.white,
border: Border(top: BorderSide(color: Color(0xFFEEEEEE), width: 1.0)),
),
unselectedLabelStyle: TextStyle(
fontFamily: 'SCDream',
fontSize: 12,
fontWeight: FontWeight.w400, // Regular
),
showUnselectedLabels: true,
items: [
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: _buildSvgIcon('assets/icons/homeicon.svg', 0),
),
label: '',
child: Theme(
data: Theme.of(context).copyWith(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: _buildSvgIcon('assets/icons/appointmenticon.svg', 1),
child: BottomNavigationBar(
backgroundColor: Colors.white,
elevation: 0, // Remove default shadow since we have a border
currentIndex: _selectedIndex,
onTap: _onItemTapped,
type: BottomNavigationBarType.fixed,
selectedItemColor: AppColors.highlight,
unselectedItemColor: AppColors.inactive,
selectedLabelStyle: TextStyle(
fontFamily: 'SCDream',
fontSize: 12.sp,
fontWeight: FontWeight.w500, // Medium
),
label: '예약/조회',
),
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Image.asset(
_selectedIndex == 2
? 'assets/img/catdog_on.png'
: 'assets/img/catdog_off.png',
width: 24,
height: 24,
unselectedLabelStyle: TextStyle(
fontFamily: 'SCDream',
fontSize: 12.sp,
fontWeight: FontWeight.w400, // Regular
),
showUnselectedLabels: true,
items: [
BottomNavigationBarItem(
icon: Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: _buildSvgIcon('assets/icons/homeicon.svg', 0),
),
label: '',
),
),
label: '멍냥즈',
BottomNavigationBarItem(
icon: Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: _buildSvgIcon('assets/icons/appointmenticon.svg', 1),
),
label: '예약/조회',
),
BottomNavigationBarItem(
icon: Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: Image.asset(
_selectedIndex == 2
? 'assets/img/catdog_on.png'
: 'assets/img/catdog_off.png',
width: 29.w,
height: 26.h,
fit: BoxFit.cover,
),
),
label: '멍냥즈',
),
BottomNavigationBarItem(
icon: Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: _buildSvgIcon('assets/icons/shopicon.svg', 3),
),
label: '상점',
),
BottomNavigationBarItem(
icon: Padding(
padding: EdgeInsets.only(bottom: 10.h),
child: _buildSvgIcon('assets/icons/myicon.svg', 4),
),
label: '내 정보',
),
],
),
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: _buildSvgIcon('assets/icons/shopicon.svg', 3),
),
label: '상점',
),
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: _buildSvgIcon('assets/icons/myicon.svg', 4),
),
label: '내 정보',
),
],
),
),
);
}

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import '../utils/log_manager.dart';
class MungNyangzScreen extends StatelessWidget {
@ -8,6 +8,7 @@ class MungNyangzScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: ValueListenableBuilder<List<String>>(
valueListenable: LogManager().logs,
@ -18,19 +19,19 @@ class MungNyangzScreen extends StatelessWidget {
);
}
return ListView.builder(
padding: const EdgeInsets.all(10),
padding: EdgeInsets.all(10.w),
itemCount: logs.length,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.only(bottom: 5),
padding: const EdgeInsets.all(8),
margin: EdgeInsets.only(bottom: 5.h),
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.circular(5),
borderRadius: BorderRadius.circular(5.r),
),
child: Text(
logs[index],
style: const TextStyle(fontSize: 12, fontFamily: 'SCDream'),
style: TextStyle(fontSize: 12.sp, fontFamily: 'SCDream'),
),
);
},

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import '../services/auth_service.dart';
import 'welcome_screen.dart';
import 'notice_screen.dart'; //
import '../data/terms_data.dart'; //
import 'notice_screen.dart';
import '../data/terms_data.dart';
class MyInfoScreen extends StatefulWidget {
const MyInfoScreen({super.key});
@ -97,10 +97,10 @@ class _MyInfoScreenState extends State<MyInfoScreen> {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent, //
backgroundColor: Colors.transparent,
builder: (context) {
return DraggableScrollableSheet(
initialChildSize: 0.85, // 85%
initialChildSize: 0.85,
minChildSize: 0.5,
maxChildSize: 0.95,
builder: (_, controller) {
@ -228,10 +228,8 @@ class _MyInfoScreenState extends State<MyInfoScreen> {
? const Center(child: Text('정보를 불러올 수 없습니다.'))
: SafeArea(
child: Column(
// Column으로
children: [
Expanded(
//
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
@ -243,10 +241,10 @@ class _MyInfoScreenState extends State<MyInfoScreen> {
color: Colors.grey[100],
borderRadius: BorderRadius.circular(16),
),
child: Column(
child: Row(
children: [
const CircleAvatar(
radius: 40,
radius: 35,
backgroundColor: Colors.grey,
child: Icon(
Icons.person,
@ -254,23 +252,28 @@ class _MyInfoScreenState extends State<MyInfoScreen> {
color: Colors.white,
),
),
const SizedBox(height: 16),
Text(
_userInfo!['nickname'] ?? '이름 없음',
style: const TextStyle(
fontFamily: 'SCDream',
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
_userInfo!['email'] ?? '이메일 없음',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 14,
color: Colors.grey[600],
),
const SizedBox(width: 20),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_userInfo!['nickname'] ?? '이름 없음',
style: const TextStyle(
fontFamily: 'SCDream',
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
_userInfo!['email'] ?? '이메일 없음',
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
],
),
@ -299,7 +302,7 @@ class _MyInfoScreenState extends State<MyInfoScreen> {
title: '버전 정보',
icon: Icons.info_outline,
trailingText: '1.0.0',
onTap: () {}, //
onTap: () {},
),
// removed from here
],

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
class NoticeScreen extends StatelessWidget {
const NoticeScreen({super.key});
@ -26,49 +27,47 @@ class NoticeScreen extends StatelessWidget {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Text(
title: Text(
'공지사항',
style: TextStyle(
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 18.sp, // Added responsive font size
),
),
centerTitle: true,
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black, size: 20),
icon: Icon(Icons.arrow_back_ios, color: Colors.black, size: 20.w),
onPressed: () => Navigator.pop(context),
),
),
body: ListView.separated(
itemCount: notices.length,
separatorBuilder: (context, index) =>
const Divider(height: 1, color: Color(0xFFEEEEEE)),
Divider(height: 1.h, color: const Color(0xFFEEEEEE)),
itemBuilder: (context, index) {
final notice = notices[index];
return ExpansionTile(
tilePadding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 8,
),
tilePadding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 8.h),
title: Text(
notice['title']!,
style: const TextStyle(
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 16,
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
subtitle: Padding(
padding: const EdgeInsets.only(top: 4),
padding: EdgeInsets.only(top: 4.h),
child: Text(
notice['date']!,
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 12,
fontSize: 12.sp,
color: Colors.grey[500],
),
),
@ -76,16 +75,13 @@ class NoticeScreen extends StatelessWidget {
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
),
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 20.h),
color: Colors.grey[50],
child: Text(
notice['content']!,
style: const TextStyle(
style: TextStyle(
fontFamily: 'SCDream',
fontSize: 14,
fontSize: 14.sp,
height: 1.5,
color: Colors.black87,
),

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@ class ReservationScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: const SafeArea(
child: Center(
child: Text(

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
class ShopScreen extends StatelessWidget {
const ShopScreen({super.key});
@ -6,11 +7,12 @@ class ShopScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: const SafeArea(
backgroundColor: Colors.white,
body: SafeArea(
child: Center(
child: Text(
'상점 화면 준비 중입니다.',
style: TextStyle(fontFamily: 'SCDream'),
style: TextStyle(fontFamily: 'SCDream', fontSize: 14.sp),
),
),
),

View File

@ -1,259 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../services/auth_service.dart';
import 'main_screen.dart';
import 'terms_agreement_screen.dart';
class SignupScreen extends StatefulWidget {
const SignupScreen({super.key});
@override
State<SignupScreen> createState() => _SignupScreenState();
}
class _SignupScreenState extends State<SignupScreen> {
bool _isLoading = false;
Future<void> _handleGoogleLogin() async {
setState(() {
_isLoading = true;
});
try {
final authService = AuthService();
// Returns Map<String, dynamic>? { 'credential': ..., 'isNewUser': bool }
final result = await authService.signInWithGoogle();
if (!mounted) return;
if (result != null) {
final isNewUser = result['isNewUser'] as bool;
if (isNewUser) {
// ->
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
TermsAgreementScreen(idToken: result['idToken']),
),
);
} else {
// ->
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const MainScreen()),
);
}
} else {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('로그인이 취소되었습니다.')));
}
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('로그인 실패: $e')));
} finally {
if (mounted) {
setState(() {
_isLoading = false;
});
}
}
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(
Icons.arrow_back_ios,
color: Colors.black,
size: 20,
),
onPressed: () => Navigator.pop(context),
),
title: const Text(
'회원가입',
style: TextStyle(
fontSize: 15,
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 240),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset('assets/img/foot.png', width: 30),
const SizedBox(width: 10),
const Text(
'간편 로그인',
style: TextStyle(
fontSize: 24,
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
],
),
const SizedBox(height: 10),
const Text(
'똑똑한 반려생활을 위한 첫걸음,\nRUP에 오신것을 환영해요!',
style: TextStyle(
fontSize: 14,
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
color: Colors.black,
),
textAlign: TextAlign.start,
),
const Spacer(),
Align(
alignment: Alignment.centerRight,
child: Image.asset('assets/img/cat.png', height: 150),
),
const SizedBox(height: 10),
],
),
),
bottomSheet: Container(
color: Colors.white,
padding: const EdgeInsets.fromLTRB(20, 20, 20, 40),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Naver Login Button
_SocialLoginButton(
text: '네이버 로그인',
textColor: Colors.white,
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
fontSize: 15,
backgroundColor: const Color(0xFF00D03F),
onPressed: () {},
iconPath: 'assets/icons/navericon.svg',
),
const SizedBox(height: 15),
// Kakao Login Button
_SocialLoginButton(
text: '카카오로 3초만에 시작하기',
textColor: const Color(0xFF212121),
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
fontSize: 15,
backgroundColor: const Color(0xFFFAE100),
onPressed: () {},
iconPath: 'assets/icons/kakaoicon.svg',
),
const SizedBox(height: 15),
// Google Login Button
_SocialLoginButton(
text: '구글 로그인',
textColor: const Color(0xFF17191A),
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
fontSize: 15,
backgroundColor: Colors.white,
onPressed: _handleGoogleLogin,
iconPath: 'assets/icons/googleicon.svg',
isBordered: true,
),
],
),
),
),
if (_isLoading)
Container(
color: Colors.black.withOpacity(0.5),
child: const Center(child: CircularProgressIndicator()),
),
],
);
}
}
class _SocialLoginButton extends StatelessWidget {
final String text;
final Color textColor;
final Color backgroundColor;
final VoidCallback onPressed;
final String iconPath;
final bool isBordered;
final String fontFamily;
final double fontSize;
final FontWeight fontWeight;
const _SocialLoginButton({
required this.text,
required this.textColor,
required this.backgroundColor,
required this.onPressed,
required this.iconPath,
this.isBordered = false,
this.fontFamily = 'SCDream',
this.fontWeight = FontWeight.w500,
this.fontSize = 16,
});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 50,
child: ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor,
foregroundColor: textColor,
elevation: 0,
shape: StadiumBorder(
side: isBordered
? BorderSide(color: Colors.grey[300]!)
: BorderSide.none,
),
padding: EdgeInsets.symmetric(horizontal: 20),
),
child: Row(
children: [
SvgPicture.asset(
iconPath,
width: 24,
height: 24,
fit: BoxFit.contain,
),
Expanded(
child: Text(
text,
style: TextStyle(
fontFamily: fontFamily,
fontWeight: fontWeight,
fontSize: fontSize,
),
textAlign: TextAlign.center,
),
),
SizedBox(width: 24),
],
),
),
);
}
}

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import 'welcome_screen.dart';
import 'main_screen.dart';
import '../services/auth_service.dart'; // Import AuthService
@ -30,16 +31,20 @@ class _SplashScreenState extends State<SplashScreen> {
if (token != null) {
// ( )
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const MainScreen()),
);
if (mounted) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const MainScreen()),
);
}
} else {
//
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const WelcomeScreen()),
);
if (mounted) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const WelcomeScreen()),
);
}
}
}
@ -51,14 +56,14 @@ class _SplashScreenState extends State<SplashScreen> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/img/maindog.png', width: 150, height: 150),
const SizedBox(height: 20),
const Text(
Image.asset('assets/img/maindog.png', width: 150.w, height: 150.h),
SizedBox(height: 20.h),
Text(
'RUP',
style: TextStyle(
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
fontSize: 32,
fontSize: 32.sp,
color: Colors.white,
),
),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import 'identity_verification_screen.dart';
import '../services/auth_service.dart'; // Import AuthService
import '../data/terms_data.dart';
@ -59,41 +60,41 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
maxChildSize: 0.9,
builder: (_, controller) {
return Container(
decoration: const BoxDecoration(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
borderRadius: BorderRadius.vertical(top: Radius.circular(20.r)),
),
padding: const EdgeInsets.all(20),
padding: EdgeInsets.all(20.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
width: 40,
height: 4,
width: 40.w,
height: 4.h,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(2),
borderRadius: BorderRadius.circular(2.r),
),
),
),
const SizedBox(height: 20),
SizedBox(height: 20.h),
Text(
title,
style: const TextStyle(
fontSize: 18,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
),
),
const SizedBox(height: 20),
SizedBox(height: 20.h),
Expanded(
child: SingleChildScrollView(
controller: controller,
child: Text(
_getTermContent(index),
style: const TextStyle(
fontSize: 15,
style: TextStyle(
fontSize: 15.sp,
height: 1.6,
fontFamily: 'SCDream',
color: Colors.black87,
@ -101,24 +102,24 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
),
),
),
const SizedBox(height: 20),
SizedBox(height: 20.h),
SizedBox(
width: double.infinity,
height: 52,
height: 52.h,
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFF7500),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
borderRadius: BorderRadius.circular(30.r),
),
elevation: 0,
),
child: const Text(
child: Text(
'확인',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
),
@ -142,14 +143,14 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black, size: 20),
icon: Icon(Icons.arrow_back_ios, color: Colors.black, size: 20.w),
onPressed: () => Navigator.pop(context),
),
title: Text(
widget.isViewOnly ? '이용 약관' : '회원가입',
style: const TextStyle(
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontSize: 16.sp,
fontWeight: FontWeight.w600,
fontFamily: 'SCDream',
),
@ -161,24 +162,24 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
children: [
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
SizedBox(height: 20.h),
// Header Area
Row(
children: [
Image.asset(
'assets/img/foot.png',
width: 24,
height: 24,
width: 24.w,
height: 24.h,
),
const SizedBox(width: 8),
const Text(
SizedBox(width: 8.w),
Text(
'서비스 이용 약관',
style: TextStyle(
fontSize: 22,
fontSize: 22.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
color: Colors.black,
@ -186,32 +187,32 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
),
],
),
const SizedBox(height: 8),
SizedBox(height: 8.h),
Text(
widget.isViewOnly
? 'RUP 서비스의 이용 약관 내용입니다.'
: '서비스 이용을 위해 약관에 동의해주세요.',
style: const TextStyle(
fontSize: 15,
style: TextStyle(
fontSize: 15.sp,
color: Colors.black54,
fontFamily: 'SCDream',
),
),
const SizedBox(height: 30),
SizedBox(height: 30.h),
// All Agree Box - *ViewOnly *
if (!widget.isViewOnly) ...[
InkWell(
onTap: () => _toggleAll(),
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(8.r),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 16,
horizontal: 16,
padding: EdgeInsets.symmetric(
vertical: 16.h,
horizontal: 16.w,
),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(8.r),
),
child: Row(
children: [
@ -223,11 +224,11 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
? const Color(0xFFFF7500)
: Colors.grey,
),
const SizedBox(width: 12),
const Text(
SizedBox(width: 12.w),
Text(
'모든 약관에 동의합니다.',
style: TextStyle(
fontSize: 16,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
),
@ -236,9 +237,9 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
),
),
),
const SizedBox(height: 20),
const Divider(height: 1, color: Color(0xFFEEEEEE)),
const SizedBox(height: 10),
SizedBox(height: 20.h),
Divider(height: 1.h, color: const Color(0xFFEEEEEE)),
SizedBox(height: 10.h),
],
// Individual Items
@ -255,10 +256,10 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
// Bottom Button
Padding(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 20),
padding: EdgeInsets.fromLTRB(20.w, 10.h, 20.w, 20.h),
child: SizedBox(
width: double.infinity,
height: 52,
height: 52.h,
child: ElevatedButton(
onPressed: widget.isViewOnly
? () => Navigator.pop(context)
@ -299,15 +300,15 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
backgroundColor: const Color(0xFFFF7500),
disabledBackgroundColor: Colors.grey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
borderRadius: BorderRadius.circular(30.r),
),
elevation: 0,
),
child: Text(
widget.isViewOnly ? '닫기' : '동의하고 본인 인증하기',
style: const TextStyle(
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontSize: 16.sp,
fontWeight: FontWeight.bold,
fontFamily: 'SCDream',
),
@ -326,7 +327,7 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
// ViewOnly ( X)
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
padding: EdgeInsets.symmetric(vertical: 4.h),
child: Row(
children: [
Expanded(
@ -339,24 +340,21 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
_showTermDetail(context, title, index);
}
},
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(8.r),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 8,
),
padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 8.w),
child: Row(
children: [
// Icon - *ViewOnly *
if (!widget.isViewOnly) ...[
Icon(
Icons.check,
size: 20,
size: 20.w,
color: _checks[index]
? const Color(0xFFFF7500)
: Colors.grey[300],
),
const SizedBox(width: 12),
SizedBox(width: 12.w),
],
Text(
@ -366,16 +364,16 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
? const Color(0xFFFF7500)
: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 14,
fontSize: 14.sp,
fontFamily: 'SCDream',
),
),
const SizedBox(width: 8),
SizedBox(width: 8.w),
Expanded(
child: Text(
title,
style: const TextStyle(
fontSize: 15,
style: TextStyle(
fontSize: 15.sp,
color: Colors.black87,
fontFamily: 'SCDream',
),
@ -388,13 +386,13 @@ class _TermsAgreementScreenState extends State<TermsAgreementScreen> {
),
IconButton(
onPressed: () => _showTermDetail(context, title, index),
icon: const Icon(
icon: Icon(
Icons.arrow_forward_ios,
size: 14,
size: 14.w,
color: Colors.black,
),
splashRadius: 20,
padding: const EdgeInsets.all(12),
splashRadius: 20.r,
padding: EdgeInsets.all(12.w),
constraints: const BoxConstraints(),
),
],

View File

@ -12,4 +12,7 @@ class AppColors {
// : #FF7500 (, !)
static const Color highlight = Color(0xFFFF7500);
// : #FBB800
static const Color subHighlight = Color(0xFFFBB800);
}

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
class IntroBody extends StatelessWidget {
const IntroBody({super.key});
@ -6,8 +7,8 @@ class IntroBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.fromLTRB(40, 0, 40, 0),
margin: EdgeInsets.only(top: 156),
padding: EdgeInsets.fromLTRB(40.w, 0, 40.w, 0),
margin: EdgeInsets.only(top: 156.h),
child: LayoutBuilder(
builder: (context, constraints) {
return FittedBox(
@ -28,7 +29,7 @@ class IntroBody extends StatelessWidget {
Text(
'Right',
style: TextStyle(
fontSize: 60,
fontSize: 60.sp,
fontFamily: 'Ownglyph',
color: Colors.white,
),
@ -36,17 +37,17 @@ class IntroBody extends StatelessWidget {
Text(
'Use for',
style: TextStyle(
fontSize: 60,
fontSize: 60.sp,
fontFamily: 'Ownglyph',
color: Colors.white,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 26),
padding: EdgeInsets.only(bottom: 26.h),
child: Text(
'Pet',
style: TextStyle(
fontSize: 60,
fontSize: 60.sp,
fontFamily: 'Ownglyph',
color: Colors.white,
),
@ -54,17 +55,26 @@ class IntroBody extends StatelessWidget {
),
],
),
Image.asset('assets/img/mainball.png'),
Image.asset(
'assets/img/mainball.png',
width: 100.w,
), // Added explicit width control
],
),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Image.asset('assets/img/maindog.png'),
Image.asset(
'assets/img/maindog.png',
width: 150.w,
), // Added explicit width control
Opacity(
opacity: 0.0,
child: Image.asset('assets/img/mainball.png'),
child: Image.asset(
'assets/img/mainball.png',
width: 100.w,
), // Added explicit width control
),
],
),

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import '../screens/signup_screen.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; // Import screenutil
import '../screens/login_screen.dart';
class LoginPanel extends StatelessWidget {
@ -9,8 +9,8 @@ class LoginPanel extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: Color(0xFFFF7500),
padding: EdgeInsets.fromLTRB(40, 0, 40, 40),
color: const Color(0xFFFF7500),
padding: EdgeInsets.fromLTRB(40.w, 0, 40.w, 40.h),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
@ -18,27 +18,27 @@ class LoginPanel extends StatelessWidget {
Text(
'간편한 반려생활을 위한 첫걸음,\nRUP에 오신것을 환영합니다!',
style: TextStyle(
fontSize: 12,
fontSize: 12.sp,
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
color: Colors.black,
),
textAlign: TextAlign.center,
),
SizedBox(height: 30),
SizedBox(height: 30.h),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SignupScreen()),
MaterialPageRoute(builder: (context) => const LoginScreen()),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
shape: StadiumBorder(),
padding: EdgeInsets.all(15),
shape: const StadiumBorder(),
padding: EdgeInsets.all(15.w),
),
child: Stack(
alignment: Alignment.center,
@ -49,7 +49,9 @@ class LoginPanel extends StatelessWidget {
'시작하기',
style: TextStyle(
fontFamily: 'SCDream',
fontWeight: FontWeight.bold,
fontWeight: FontWeight
.bold, // Fixed typo in previous code if any, bold is correct
fontSize: 14.sp, // Added font size
color: Colors.black,
),
),
@ -58,27 +60,6 @@ class LoginPanel extends StatelessWidget {
),
),
),
SizedBox(height: 5),
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
);
},
child: Text(
'기존 계정으로 로그인',
style: TextStyle(
fontFamily: 'SCDream',
fontWeight: FontWeight.w500,
fontSize: 12,
color: Colors.white,
decoration: TextDecoration.underline,
decorationColor: Colors.white,
),
),
),
],
),
);

View File

@ -6,9 +6,13 @@
#include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
flutter_secure_storage_linux
)

View File

@ -5,6 +5,7 @@
import FlutterMacOS
import Foundation
import file_selector_macos
import firebase_auth
import firebase_core
import flutter_secure_storage_macos
@ -12,6 +13,7 @@ import google_sign_in_ios
import video_player_avfoundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))

View File

@ -65,6 +65,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.19.1"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: "701dcfc06da0882883a2657c445103380e53e647060ad8d9dfb710c100996608"
url: "https://pub.dev"
source: hosted
version: "0.3.5+1"
crypto:
dependency: transitive
description:
@ -129,6 +137,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.1"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0"
url: "https://pub.dev"
source: hosted
version: "0.9.4"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a"
url: "https://pub.dev"
source: hosted
version: "0.9.5"
file_selector_platform_interface:
dependency: transitive
description:
name: file_selector_platform_interface
sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85"
url: "https://pub.dev"
source: hosted
version: "2.7.0"
file_selector_windows:
dependency: transitive
description:
name: file_selector_windows
sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd"
url: "https://pub.dev"
source: hosted
version: "0.9.3+5"
firebase_auth:
dependency: "direct main"
description:
@ -190,6 +230,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1
url: "https://pub.dev"
source: hosted
version: "2.0.33"
flutter_screenutil:
dependency: "direct main"
description:
name: flutter_screenutil
sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de"
url: "https://pub.dev"
source: hosted
version: "5.9.3"
flutter_secure_storage:
dependency: "direct main"
description:
@ -344,6 +400,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.1.2"
image_picker:
dependency: "direct main"
description:
name: image_picker
sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
sha256: "297e42bd236c4ac4b091d4277292159b3280545e030cae2be3d503f9ecf7e6a1"
url: "https://pub.dev"
source: hosted
version: "0.8.13+12"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: "956c16a42c0c708f914021666ffcd8265dde36e673c9fa68c81f7d085d9774ad"
url: "https://pub.dev"
source: hosted
version: "0.8.13+3"
image_picker_linux:
dependency: transitive
description:
name: image_picker_linux
sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
url: "https://pub.dev"
source: hosted
version: "0.2.2"
image_picker_macos:
dependency: transitive
description:
name: image_picker_macos
sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91"
url: "https://pub.dev"
source: hosted
version: "0.2.2+1"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c"
url: "https://pub.dev"
source: hosted
version: "2.11.1"
image_picker_windows:
dependency: transitive
description:
name: image_picker_windows
sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
url: "https://pub.dev"
source: hosted
version: "0.2.2"
js:
dependency: transitive
description:

View File

@ -41,6 +41,8 @@ dependencies:
google_sign_in: ^6.2.1 # 구글 로그인 UI/기능 (Updated)
dio: ^5.4.0
flutter_secure_storage: ^9.0.0
image_picker: ^1.2.1
flutter_screenutil: ^5.9.3
dev_dependencies:
flutter_test:

View File

@ -6,11 +6,14 @@
#include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <firebase_auth/firebase_auth_plugin_c_api.h>
#include <firebase_core/firebase_core_plugin_c_api.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
FirebaseAuthPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi"));
FirebaseCorePluginCApiRegisterWithRegistrar(

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
firebase_auth
firebase_core
flutter_secure_storage_windows