From fb150ed276fc5956cd7e74ca9b4cfda27a2a15d1 Mon Sep 17 00:00:00 2001 From: HuiChan Seo <78739194+seochan99@users.noreply.github.com> Date: Sun, 18 Feb 2024 02:48:02 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=92=84Style=20:=20safeArea=20backgoru?= =?UTF-8?q?nd=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/views/base/base_screen.dart | 2 +- lib/views/home/home_screen.dart | 296 +++++++++--------- lib/views/profile/profile_screen.dart | 7 +- .../root/custom_bottom_navigation_bar.dart | 4 +- lib/views/root/root_screen.dart | 65 ++-- 5 files changed, 185 insertions(+), 189 deletions(-) diff --git a/lib/views/base/base_screen.dart b/lib/views/base/base_screen.dart index 497d098..8e72ebf 100644 --- a/lib/views/base/base_screen.dart +++ b/lib/views/base/base_screen.dart @@ -83,7 +83,7 @@ abstract class BaseScreen extends GetView { // SafeArea의 위 부분을 설정할지 여부를 정의하는 메서드 @protected - bool get setTopSafeArea => true; + bool get setTopSafeArea => false; // AppBar를 구성하는 메서드 @protected diff --git a/lib/views/home/home_screen.dart b/lib/views/home/home_screen.dart index 2cb3a57..6db2922 100644 --- a/lib/views/home/home_screen.dart +++ b/lib/views/home/home_screen.dart @@ -3,7 +3,6 @@ import 'package:earlips/viewModels/home/home_viewmodel.dart'; import 'package:earlips/views/base/base_screen.dart'; import 'package:get/get.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:fl_chart/fl_chart.dart'; import 'package:earlips/views/home/widget/study_chart.dart'; import 'package:percent_indicator/percent_indicator.dart'; //dart.ui @@ -18,8 +17,9 @@ class HomeScreen extends BaseScreen { @override Widget buildBody(BuildContext context) { return Scaffold( - backgroundColor: Color(0xFFF0F4F8), + backgroundColor: const Color(0xFFF0F4F8), body: SafeArea( + top: true, child: StreamBuilder( stream: FirebaseAuth.instance.authStateChanges(), builder: (context, snapshot) { @@ -27,9 +27,9 @@ class HomeScreen extends BaseScreen { return SingleChildScrollView( child: Column( children: [ - _Header(), - _Top(), - _Middle(), + const _Header(), + const _Top(), + const _Middle(), // 로그인 상태에 따라 _Bottom 클래스의 컨테이너 색상을 변경 _Bottom(isLoggedIn: isLoggedIn), ], @@ -52,33 +52,34 @@ class _Header extends StatelessWidget { Container( //왼쪽으로 정렬 alignment: Alignment.centerLeft, - margin: EdgeInsets.only(left: 20.0, top: 20.0), + margin: const EdgeInsets.only(left: 20.0, top: 20.0), - child: Text("오늘도 열심히 해볼까요?", - style: TextStyle( - fontFamily: 'Pretendard-Bold', - fontSize: 25, - //weight - fontWeight: FontWeight.bold, - ), + child: const Text( + "오늘도 열심히 해볼까요?", + style: TextStyle( + fontFamily: 'Pretendard-Bold', + fontSize: 25, + //weight + fontWeight: FontWeight.bold, + ), ), ), Container( alignment: Alignment.centerLeft, - margin: EdgeInsets.only(left: 20.0), + margin: const EdgeInsets.only(left: 20.0), child: Row( mainAxisSize: MainAxisSize.min, // Row의 크기를 내용물에 맞게 조정 children: [ Container( - margin: EdgeInsets.only(right: 8.0), // 점과 텍스트 사이의 간격 조정 + margin: const EdgeInsets.only(right: 8.0), // 점과 텍스트 사이의 간격 조정 height: 10.0, // 점의 높이 width: 10.0, // 점의 너비 - decoration: BoxDecoration( + decoration: const BoxDecoration( color: Colors.green, // 점의 색상을 초록색으로 설정 shape: BoxShape.circle, // 원형으로 점을 만듭니다 ), ), - Text( + const Text( "korean - Bunju", style: TextStyle( fontFamily: 'Pretendard-Regular', @@ -88,8 +89,6 @@ class _Header extends StatelessWidget { ], ), ) - - ], ); } @@ -102,19 +101,17 @@ class _Top extends StatelessWidget { Widget build(BuildContext context) { return Center( child: Container( - margin: EdgeInsets.all(20.0), - decoration: BoxDecoration( - color: Color(0xFFFFFFFF), - borderRadius: BorderRadius.circular(30.0), - ), - - height: Get.height * 0.19, - child: Row(children: [ - _Circle(), - _SpeakingAbility(), - ]), - ) - ); + margin: const EdgeInsets.all(20.0), + decoration: BoxDecoration( + color: const Color(0xFFFFFFFF), + borderRadius: BorderRadius.circular(30.0), + ), + height: Get.height * 0.19, + child: const Row(children: [ + _Circle(), + _SpeakingAbility(), + ]), + )); } } @@ -123,92 +120,91 @@ class _Middle extends StatelessWidget { @override Widget build(BuildContext context) { - return Row( - children:[ - InkWell( - onTap: () { - Get.to(() => LearningSessionScreen()); - }, - child: Container( - margin: EdgeInsets.only(left: 20.0), - height: Get.height * 0.21, - width: Get.width * 0.43, - decoration: BoxDecoration( - color: Color(0xFFFFFFFF), - borderRadius: BorderRadius.circular(30.0), - ), - child: Column( - children: [ - Container( - alignment: Alignment.center, - margin: EdgeInsets.only(top: 20.0, bottom: 10.0), - child: Image.asset('assets/images/home/Chart_new.png'), - width: 90, - height: 90, - ), - Text( - "대본으로 학습하기", - style: TextStyle( - fontFamily: 'Pretendard-Bold', - fontSize: 15, - fontWeight: FontWeight.bold, - ), + return Row(children: [ + InkWell( + onTap: () { + Get.to(() => LearningSessionScreen()); + }, + child: Container( + margin: const EdgeInsets.only(left: 20.0), + height: Get.height * 0.21, + width: Get.width * 0.43, + decoration: BoxDecoration( + color: const Color(0xFFFFFFFF), + borderRadius: BorderRadius.circular(30.0), + ), + child: Column( + children: [ + Container( + alignment: Alignment.center, + margin: const EdgeInsets.only(top: 20.0, bottom: 10.0), + width: 90, + height: 90, + child: Image.asset('assets/images/home/Chart_new.png'), + ), + const Text( + "대본으로 학습하기", + style: TextStyle( + fontFamily: 'Pretendard-Bold', + fontSize: 15, + fontWeight: FontWeight.bold, ), - Text( - "대본 입력 및 발음 테스트", - style: TextStyle( - fontFamily: 'Pretendard-Regular', - fontSize: 12, - ), + ), + const Text( + "대본 입력 및 발음 테스트", + style: TextStyle( + fontFamily: 'Pretendard-Regular', + fontSize: 12, ), - ], - ), + ), + ], ), ), - InkWell( - onTap: () { - Get.to(() => RealCreateScriptPage()); // Adjust the screen name as necessary - }, - child: Container( - margin: EdgeInsets.only(left: 20.0), - height: Get.height * 0.21, - width: Get.width * 0.43, - decoration: BoxDecoration( - color: Color(0xFFFFFFFF), - borderRadius: BorderRadius.circular(30.0), - ), - child: Column( - children: [ - Container( - alignment: Alignment.center, - margin: EdgeInsets.only(top: 20.0, bottom: 10.0), - child: SvgPicture.asset( - 'assets/images/home/three_circle.svg', - width: 85, - height: 85, - ), + ), + InkWell( + onTap: () { + Get.to(() => + RealCreateScriptPage()); // Adjust the screen name as necessary + }, + child: Container( + margin: const EdgeInsets.only(left: 20.0), + height: Get.height * 0.21, + width: Get.width * 0.43, + decoration: BoxDecoration( + color: const Color(0xFFFFFFFF), + borderRadius: BorderRadius.circular(30.0), + ), + child: Column( + children: [ + Container( + alignment: Alignment.center, + margin: const EdgeInsets.only(top: 20.0, bottom: 10.0), + child: SvgPicture.asset( + 'assets/images/home/three_circle.svg', + width: 85, + height: 85, ), - Text( - "실시간 발음테스트", - style: TextStyle( - fontFamily: 'Pretendard-Bold', - fontSize: 15, - fontWeight: FontWeight.bold, - ), + ), + const Text( + "실시간 발음테스트", + style: TextStyle( + fontFamily: 'Pretendard-Bold', + fontSize: 15, + fontWeight: FontWeight.bold, ), - Text( - "음성 인식 및 발음 테스트", - style: TextStyle( - fontFamily: 'Pretendard-Regular', - fontSize: 12, - ), + ), + const Text( + "음성 인식 및 발음 테스트", + style: TextStyle( + fontFamily: 'Pretendard-Regular', + fontSize: 12, ), - ], - ), + ), + ], ), - ) - ] - ); + ), + ) + ]); } } @@ -221,17 +217,17 @@ class _Bottom extends StatelessWidget { return Stack( children: [ Container( - margin: EdgeInsets.all(20.0), + margin: const EdgeInsets.all(20.0), decoration: BoxDecoration( - color: Color(0xFFFFFFFF), // 기본 배경색 + color: const Color(0xFFFFFFFF), // 기본 배경색 borderRadius: BorderRadius.circular(30.0), ), child: Column( children: [ Container( - margin: EdgeInsets.only(top: 20.0, left: 20.0), + margin: const EdgeInsets.only(top: 20.0, left: 20.0), alignment: Alignment.centerLeft, - child: Text( + child: const Text( "진행한 학습", style: TextStyle( fontFamily: 'Pretendard-Bold', @@ -240,7 +236,7 @@ class _Bottom extends StatelessWidget { ), ), ), - LineChartSample2(), + const LineChartSample2(), ], ), ), @@ -266,6 +262,7 @@ class _Bottom extends StatelessWidget { ); } } + class _Circle extends StatelessWidget { const _Circle({super.key}); @@ -276,7 +273,7 @@ class _Circle extends StatelessWidget { return Container( alignment: Alignment.centerLeft, - margin: EdgeInsets.only(left: 20.0), + margin: const EdgeInsets.only(left: 20.0), child: Stack( alignment: Alignment.center, children: [ @@ -286,14 +283,14 @@ class _Circle extends StatelessWidget { height: 110, ), Obx(() => Text( - homeViewModel.circleNumber.toString(), // Observable 값을 사용 - style: TextStyle( - fontFamily: 'Pretendard-Bold', - color: Colors.white, - fontSize: 28, - fontWeight: FontWeight.w900, - ), - )), + homeViewModel.circleNumber.toString(), // Observable 값을 사용 + style: const TextStyle( + fontFamily: 'Pretendard-Bold', + color: Colors.white, + fontSize: 28, + fontWeight: FontWeight.w900, + ), + )), ], ), ); @@ -311,8 +308,8 @@ class _SpeakingAbility extends StatelessWidget { return Column( children: [ Container( - margin: EdgeInsets.only(top: 35.0, right: 25.0, left: 40.0), - child: Text( + margin: const EdgeInsets.only(top: 35.0, right: 25.0, left: 40.0), + child: const Text( "Speaking Ability", style: TextStyle( fontSize: 20, @@ -322,37 +319,38 @@ class _SpeakingAbility extends StatelessWidget { ), ), Container( - margin: EdgeInsets.only(top: 0.0, right: 25.0, left: 40.0), + margin: const EdgeInsets.only(top: 0.0, right: 25.0, left: 40.0), child: Row( children: [ Obx(() => Text( - "발음 ${homeViewModel.speakingScore}", - style: TextStyle( - fontFamily: 'Pretendard-Regular', - fontSize: 15, - ), - )), - SizedBox(width: 30), + "발음 ${homeViewModel.speakingScore}", + style: const TextStyle( + fontFamily: 'Pretendard-Regular', + fontSize: 15, + ), + )), + const SizedBox(width: 30), Obx(() => Text( - "높낮이 ${homeViewModel.pitchScore}", - style: TextStyle( - fontFamily: 'Pretendard-Regular', - fontSize: 15, - ), - )), + "높낮이 ${homeViewModel.pitchScore}", + style: const TextStyle( + fontFamily: 'Pretendard-Regular', + fontSize: 15, + ), + )), ], ), ), - Obx(() => Container( - margin: EdgeInsets.only(top: 20.0, left: 20.0), - child: LinearPercentIndicator( - barRadius: Radius.circular(10.0), - width: 163.0, - lineHeight: 8.0, - percent: homeViewModel.linialPersent.value, - progressColor: Color(0xFF4EC040), + Obx( + () => Container( + margin: const EdgeInsets.only(top: 20.0, left: 20.0), + child: LinearPercentIndicator( + barRadius: const Radius.circular(10.0), + width: 163.0, + lineHeight: 8.0, + percent: homeViewModel.linialPersent.value, + progressColor: const Color(0xFF4EC040), + ), ), - ), ) ], ); diff --git a/lib/views/profile/profile_screen.dart b/lib/views/profile/profile_screen.dart index 7a14767..0006dfc 100644 --- a/lib/views/profile/profile_screen.dart +++ b/lib/views/profile/profile_screen.dart @@ -12,9 +12,10 @@ class ProfileScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - body: Container( - color: ColorSystem.white, - child: SafeArea( + body: SafeArea( + top: true, + child: Container( + color: ColorSystem.white, child: StreamBuilder( stream: FirebaseAuth.instance.authStateChanges(), builder: (context, snapshot) { diff --git a/lib/views/root/custom_bottom_navigation_bar.dart b/lib/views/root/custom_bottom_navigation_bar.dart index 5d5b037..2b38418 100644 --- a/lib/views/root/custom_bottom_navigation_bar.dart +++ b/lib/views/root/custom_bottom_navigation_bar.dart @@ -1,4 +1,3 @@ -import 'package:earlips/utilities/style/color_styles.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; @@ -11,7 +10,7 @@ class CustomBottomNavigationBar extends BaseWidget { @override Widget buildView(BuildContext context) { return Obx( - () => Theme( + () => Theme( data: ThemeData( highlightColor: Colors.transparent, splashFactory: NoSplash.splashFactory, @@ -33,7 +32,6 @@ class CustomBottomNavigationBar extends BaseWidget { size: 60, svgPath: 'assets/icons/learning.svg', ), - const SizedBox(width: 70), _buildBottomNavigationBarItem( index: 1, diff --git a/lib/views/root/root_screen.dart b/lib/views/root/root_screen.dart index bcdffc4..a8cf094 100644 --- a/lib/views/root/root_screen.dart +++ b/lib/views/root/root_screen.dart @@ -7,13 +7,12 @@ import '../../utilities/app_routes.dart'; import '../../viewModels/root/root_viewmodel.dart'; import '../base/base_screen.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:earlips/views/study/study_main.dart'; class RootScreen extends BaseScreen { const RootScreen({super.key}); @override - Color? get screenBackgroundColor => Color(0xFFAAA4F8); + Color? get screenBackgroundColor => const Color(0xFFAAA4F8); @override Widget buildBody(BuildContext context) { @@ -35,36 +34,36 @@ class RootScreen extends BaseScreen { @override Widget? get buildFloatingActionButton => Container( - width: 70, - decoration: const BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Color(0xFF1FA9DC), - Color(0xFF1FA9DC), - Color(0xFF1FA9DC), - ], - stops: [0, 0.5, 1], - ), - ), - child: FloatingActionButton.large( - onPressed: () { - Get.toNamed(Routes.HOME); - }, - elevation: 0, - highlightElevation: 2, - shape: const CircleBorder(), - backgroundColor: Colors.transparent, - splashColor: const Color(0xFF98E3FF), - child: SvgPicture.asset( - 'assets/icons/house.svg', - fit: BoxFit.scaleDown, - color: Colors.white, - ), - ), - ); + width: 70, + decoration: const BoxDecoration( + shape: BoxShape.circle, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF1FA9DC), + Color(0xFF1FA9DC), + Color(0xFF1FA9DC), + ], + stops: [0, 0.5, 1], + ), + ), + child: FloatingActionButton.large( + onPressed: () { + Get.toNamed(Routes.HOME); + }, + elevation: 0, + highlightElevation: 2, + shape: const CircleBorder(), + backgroundColor: Colors.transparent, + splashColor: const Color(0xFF98E3FF), + child: SvgPicture.asset( + 'assets/icons/house.svg', + fit: BoxFit.scaleDown, + color: Colors.white, + ), + ), + ); @override FloatingActionButtonLocation? get floatingActionButtonLocation => @@ -74,7 +73,7 @@ class RootScreen extends BaseScreen { bool get extendBodyBehindAppBar => true; @override - Color? get unSafeAreaColor => const Color(0xFFF0F4F8); + Color? get unSafeAreaColor => const Color(0xFFFFFFFF); @override bool get setTopOuterSafeArea => false; From 80afec130fcc6bf3f83d002ae72a6347e8f544f0 Mon Sep 17 00:00:00 2001 From: HuiChan Seo <78739194+seochan99@users.noreply.github.com> Date: Sun, 18 Feb 2024 02:48:37 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=A8Feat:=20localization=20easy=20?= =?UTF-8?q?=EC=85=8B=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/translations/en-US.json | 5 + assets/translations/ko-KR.json | 5 + ios/Podfile.lock | 17 ++- ios/Runner/Info.plist | 5 + lib/main.dart | 17 ++- lib/main_app.dart | 15 +-- .../profile_language_setting.dart | 115 +++++++++--------- pubspec.yaml | 3 + 8 files changed, 113 insertions(+), 69 deletions(-) create mode 100644 assets/translations/en-US.json create mode 100644 assets/translations/ko-KR.json diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json new file mode 100644 index 0000000..00bbb29 --- /dev/null +++ b/assets/translations/en-US.json @@ -0,0 +1,5 @@ +{ + "language_settings": "Language Settings", + "system_language": "System Language", + "learning_language": "Learning Language" +} diff --git a/assets/translations/ko-KR.json b/assets/translations/ko-KR.json new file mode 100644 index 0000000..4c426ce --- /dev/null +++ b/assets/translations/ko-KR.json @@ -0,0 +1,5 @@ +{ + "language_settings": "언어 설정", + "system_language": "시스템 언어", + "learning_language": "학습 언어" +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9c235df..d95a33d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -709,6 +709,8 @@ PODS: - nanopb (< 2.30910.0, >= 2.30908.0) - FirebaseSharedSwift (10.21.0) - Flutter (1.0.0) + - flutter_localization (0.0.1): + - Flutter - flutter_native_splash (0.0.1): - Flutter - flutter_secure_storage (6.0.0): @@ -818,6 +820,9 @@ PODS: - Flutter - PromisesObjC (2.3.1) - RecaptchaInterop (100.0.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS - speech_to_text (0.0.1): - Flutter - Try @@ -829,12 +834,14 @@ DEPENDENCIES: - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_database (from `.symlinks/plugins/firebase_database/ios`) - Flutter (from `Flutter`) + - flutter_localization (from `.symlinks/plugins/flutter_localization/ios`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler (from `.symlinks/plugins/permission_handler/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - speech_to_text (from `.symlinks/plugins/speech_to_text/ios`) SPEC REPOS: @@ -876,6 +883,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_database/ios" Flutter: :path: Flutter + flutter_localization: + :path: ".symlinks/plugins/flutter_localization/ios" flutter_native_splash: :path: ".symlinks/plugins/flutter_native_splash/ios" flutter_secure_storage: @@ -888,6 +897,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler: :path: ".symlinks/plugins/permission_handler/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" speech_to_text: :path: ".symlinks/plugins/speech_to_text/ios" @@ -909,7 +920,8 @@ SPEC CHECKSUMS: FirebaseFirestore: 21be9ea244830f6cac15464550c2975c43f9dffc FirebaseFirestoreInternal: 7ac1e0c5b4e75aeb898dfe4b1d6d77abbac9eca3 FirebaseSharedSwift: 19b3f709993d6fa1d84941d41c01e3c4c11eab93 - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_localization: f43b18844a2b3d2c71fd64f04ffd6b1e64dd54d4 flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be flutter_sound: c60effa2a350fb977885f0db2fbc4c1ad5160900 @@ -927,9 +939,10 @@ SPEC CHECKSUMS: permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21 + shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 speech_to_text: b43a7d99aef037bd758ed8e45d79bbac035d2dfe Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96 PODFILE CHECKSUM: 0b2c97823421f8b156b8e4753a469ac167670df8 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index ded5ed6..2418583 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -33,6 +33,11 @@ + CFBundleLocalizations + + en + ko + CFBundleVersion $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS diff --git a/lib/main.dart b/lib/main.dart index 184a345..f08d9ab 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:earlips/firebase_options.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; @@ -9,10 +10,24 @@ void main() async { /* Open .env file */ await dotenv.load(fileName: "assets/config/.env"); await initializeDateFormatting(); + await EasyLocalization.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); - runApp(const MainApp(initialRoute: "/")); + runApp(EasyLocalization( + // 지원 언어 리스트 + supportedLocales: const [ + Locale('ko', 'KR'), + Locale('en', 'US'), + ], + //path: 언어 파일 경로 + path: 'assets/translations', + //fallbackLocale supportedLocales에 설정한 언어가 없는 경우 설정되는 언어 + fallbackLocale: const Locale('en', 'US'), + //startLocale을 지정하면 초기 언어가 설정한 언어로 변경됨 + //만일 이 설정을 하지 않으면 OS 언어를 따라 기본 언어가 설정됨 + //startLocale: Locale('ko', 'KR') + child: const MainApp(initialRoute: "/"))); } diff --git a/lib/main_app.dart b/lib/main_app.dart index 788d351..dc4b989 100644 --- a/lib/main_app.dart +++ b/lib/main_app.dart @@ -1,6 +1,3 @@ -import 'package:earlips/views/profile/profile_account/profile_account_screen.dart'; -import 'package:earlips/views/profile/profile_language_setting/profile_language_setting.dart'; -import 'package:earlips/views/profile/profile_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; @@ -9,7 +6,6 @@ import 'package:earlips/bindings/root_binding.dart'; import 'views/root/root_screen.dart'; import 'utilities/app_routes.dart'; - class MainApp extends StatelessWidget { final String initialRoute; @@ -32,6 +28,7 @@ class MainApp extends StatelessWidget { ], supportedLocales: const [ Locale('ko', 'KR'), + Locale('en', 'US'), ], theme: ThemeData( useMaterial3: true, @@ -43,13 +40,9 @@ class MainApp extends StatelessWidget { getPages: [ GetPage( name: '/', page: () => const RootScreen(), binding: RootBinding()), - // binding: - GetPage(name: '/profile', page: () => const ProfileScreen()), - GetPage( - name: '/profile/account', page: () => const ProfileAccountScreen()), - GetPage( - name: '/profile/language-setting', - page: () => const ProfileLanguageScreen()), + Routes.routes[1], + Routes.routes[2], + Routes.routes[3], ], ); } diff --git a/lib/views/profile/profile_language_setting/profile_language_setting.dart b/lib/views/profile/profile_language_setting/profile_language_setting.dart index 323012c..f68ed95 100644 --- a/lib/views/profile/profile_language_setting/profile_language_setting.dart +++ b/lib/views/profile/profile_language_setting/profile_language_setting.dart @@ -2,6 +2,7 @@ import 'package:earlips/utilities/style/color_styles.dart'; import 'package:earlips/viewModels/user/user_viewmodel.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:easy_localization/easy_localization.dart'; class ProfileLanguageScreen extends StatelessWidget { const ProfileLanguageScreen({super.key}); @@ -11,79 +12,83 @@ class ProfileLanguageScreen extends StatelessWidget { final userViewModel = Get.find(); userViewModel.loadLanguageSettings(); - String title = userViewModel.systemLanguage.value == '한국어' - ? '언어 설정' - : 'Language Settings'; - - // systemLanguage, learningLanguage - String systemLanguage = userViewModel.systemLanguage.value == '한국어' - ? '시스템 언어' - : 'System Language'; - - String learningLanguage = userViewModel.systemLanguage.value == '한국어' - ? '학습 언어' - : 'Learning Language'; + String title = tr('language_settings'); + String systemLanguage = tr('system_language'); + String learningLanguage = tr('learning_language'); return Scaffold( appBar: AppBar( title: Text(title), ), - body: Column( - children: [ - _buildLanguageSettingSection( - title: systemLanguage, - selectedLanguage: userViewModel.systemLanguage, - onLanguageSelected: (value) { - userViewModel.systemLanguage.value = value!; - userViewModel.updateLanguageSettings(); - }, - languageOptions: [ - const DropdownMenuItem(value: '한국어', child: Text('한국어')), - const DropdownMenuItem(value: 'English', child: Text('English')), - ], - ), - _buildLanguageSettingSection( - title: learningLanguage, - selectedLanguage: userViewModel.learningLanguage, - onLanguageSelected: (value) { - userViewModel.learningLanguage.value = value!; - userViewModel.updateLanguageSettings(); - }, - languageOptions: [ - const DropdownMenuItem(value: '한국어', child: Text('한국어')), - const DropdownMenuItem(value: 'English', child: Text('English')), + body: Container( + width: double.infinity, + color: ColorSystem.white, + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildLanguageSettingSection( + title: systemLanguage, + selectedLanguage: userViewModel.systemLanguage, + onLanguageSelected: (value) { + userViewModel.systemLanguage.value = value!; + userViewModel.updateLanguageSettings(); + }, + languageOptions: [ + const DropdownMenuItem(value: '한국어', child: Text('한국어')), + const DropdownMenuItem( + value: 'English', child: Text('English')), + ], + ), + const SizedBox(height: 20), + _buildLanguageSettingSection( + title: learningLanguage, + selectedLanguage: userViewModel.learningLanguage, + onLanguageSelected: (value) { + userViewModel.learningLanguage.value = value!; + userViewModel.updateLanguageSettings(); + }, + languageOptions: [ + const DropdownMenuItem(value: '한국어', child: Text('한국어')), + const DropdownMenuItem( + value: 'English', child: Text('English')), + ], + ), ], ), - ], + ), ), ); } // 셋팅 섹션 위젯 +// 셋팅 섹션 위젯 Widget _buildLanguageSettingSection({ required String title, required RxString selectedLanguage, required Function(String?) onLanguageSelected, required List> languageOptions, }) { - return Container( - margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - border: Border.all(color: ColorSystem.gray1), - ), - child: Column( - children: [ - Text(title, style: const TextStyle(fontSize: 16)), - const SizedBox(height: 10), - Obx(() => DropdownButton( - value: selectedLanguage.value, - items: languageOptions, - onChanged: onLanguageSelected, - )), - ], - ), + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500)), + const SizedBox(height: 10), + Obx(() => DropdownButton( + value: selectedLanguage.value, + items: languageOptions, + onChanged: (newValue) { + onLanguageSelected(newValue); + // Call your language change logic here + // For example: + // userViewModel.systemLanguage.value = newValue!; + // userViewModel.updateLanguageSettings(); + }, + hint: Text(tr('select_language') ?? 'fallback_language'), + )), + ], ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 2b60bb3..aa8eb84 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,8 @@ dependencies: firebase_database: ^10.4.5 cloud_firestore: ^4.15.4 http: ^1.2.0 + flutter_localization: ^0.2.0 + easy_localization: ^3.0.4 dev_dependencies: flutter_test: @@ -48,6 +50,7 @@ flutter: assets: - assets/images/ - assets/icons/ + - assets/translations/ - assets/config/.env - assets/data/ - assets/images/home/ From 5b8d50d08e4ffba7553d9921b0e2d41b37d8eec1 Mon Sep 17 00:00:00 2001 From: HuiChan Seo <78739194+seochan99@users.noreply.github.com> Date: Sun, 18 Feb 2024 02:48:48 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9C=A8=20feat:=20AppRouter=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/utilities/app_routes.dart | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/utilities/app_routes.dart b/lib/utilities/app_routes.dart index a0ed7a1..e4fcb59 100644 --- a/lib/utilities/app_routes.dart +++ b/lib/utilities/app_routes.dart @@ -1,20 +1,36 @@ // ignore_for_file: constant_identifier_names import 'package:earlips/views/home/home_screen.dart'; +import 'package:earlips/views/profile/profile_account/profile_account_screen.dart'; +import 'package:earlips/views/profile/profile_language_setting/profile_language_setting.dart'; +import 'package:earlips/views/profile/profile_screen.dart'; import 'package:get/get.dart'; - abstract class Routes { static const ROOT = '/'; static const HOME = '/home'; static const SETTING = '/setting'; static const ONBOARDING = '/onboarding'; + static const PROFILE = '/profile'; + static const PROFILE_ACCOUNT = '/profile/account'; + static const PROFILE_LANGUAGE_SETTING = '/profile/language-setting'; static final routes = [ GetPage( name: HOME, - page: () => HomeScreen(), + page: () => const HomeScreen(), + ), + GetPage( + name: PROFILE, + page: () => const ProfileScreen(), + ), + GetPage( + name: PROFILE_ACCOUNT, + page: () => const ProfileAccountScreen(), + ), + GetPage( + name: PROFILE_LANGUAGE_SETTING, + page: () => const ProfileLanguageScreen(), ), // 다른 라우트들도 이곳에 추가할 수 있습니다. ]; - -} \ No newline at end of file +}