From faaaf0a87e7778850310cd8bd228a10db38da1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=A5=EC=8A=B9=ED=98=B8?= Date: Fri, 11 Aug 2023 01:45:08 +0900 Subject: [PATCH 1/5] add Language Setting --- assets/translations/en.json | 2 ++ assets/translations/ko.json | 2 ++ lib/pages/settings_page.dart | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/assets/translations/en.json b/assets/translations/en.json index 76a99f5e..523226dc 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -136,6 +136,8 @@ "deleted_account": "This is the deleted account." }, "settings": { + "language": "Language", + "current_language": "English", "send_error_log": "Send error log", "send_error_log_desc": "Automatically collect logs without user reporting", "send_anonymously": "Send anonymously", diff --git a/assets/translations/ko.json b/assets/translations/ko.json index 1ec81329..c3c6f014 100644 --- a/assets/translations/ko.json +++ b/assets/translations/ko.json @@ -136,6 +136,8 @@ "deleted_account": "삭제된 계정입니다." }, "settings": { + "language": "언어", + "current_language": "한국어", "send_error_log": "오류 로그 전송", "send_error_log_desc": "사용자의 제보 없이 자동으로 오류를 수집합니다.", "send_anonymously": "익명으로 전송", diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index 85b0b22c..a60eba9e 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -25,6 +25,27 @@ class SettingsPage extends StatelessWidget { padding: const EdgeInsets.all(16.0), child: Column( children: [ + ListTile( + title: Text( + "settings.language".tr(), + style: bodyBold, + ), + subtitle: Text( + "settings.current_language".tr(), + style: bodyRegular, + ), + trailing: PlatformSwitch( + value: EasyLocalization.of(context)?.currentLocale == + Locale("en"), + onChanged: (value) { + if (value) { + EasyLocalization.of(context)?.setLocale(Locale('en')); + } else { + EasyLocalization.of(context)?.setLocale(Locale('ko')); + } + }, + ), + ), ListTile( title: Text( "settings.send_error_log".tr(), From 27b110fd02d41091da0020b4d4666c6f3a612d70 Mon Sep 17 00:00:00 2001 From: SungyeopJeong Date: Sat, 2 Sep 2023 04:23:32 +0900 Subject: [PATCH 2/5] feat: modify settings page ListTile design --- assets/translations/en.json | 3 +- assets/translations/ko.json | 3 +- lib/pages/settings_page.dart | 134 ++++++++++++++++++++--------------- 3 files changed, 79 insertions(+), 61 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index 523226dc..b27386ae 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -145,7 +145,8 @@ "reset_all": "Reset all settings", "reset_all_desc": "Are you really want to reset all data except login data?", "throw_test": "Throw Test Exception", - "throw_test_desc": "for testing firebase crashlytics" + "throw_test_desc": "for testing firebase crashlytics", + "about": "About" }, "department": { "department": "Dept.", diff --git a/assets/translations/ko.json b/assets/translations/ko.json index c3c6f014..2186e25c 100644 --- a/assets/translations/ko.json +++ b/assets/translations/ko.json @@ -145,7 +145,8 @@ "reset_all": "모든 설정 데이터 초기화", "reset_all_desc": "정말 모든 설정 데이터를 초기화하시겠습니까? 로그인 정보는 초기화되지 않습니다.", "throw_test": "테스트 오류 발생", - "throw_test_desc": "Firebase crashlytics 테스트용" + "throw_test_desc": "Firebase crashlytics 테스트용", + "about": "정보" }, "department": { "department": "학과", diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index a60eba9e..b8db0ef2 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:flutter/cupertino.dart'; import 'package:otlplus/constants/color.dart'; import 'package:otlplus/constants/text_styles.dart'; import 'package:otlplus/providers/settings_model.dart'; @@ -25,16 +25,10 @@ class SettingsPage extends StatelessWidget { padding: const EdgeInsets.all(16.0), child: Column( children: [ - ListTile( - title: Text( - "settings.language".tr(), - style: bodyBold, - ), - subtitle: Text( - "settings.current_language".tr(), - style: bodyRegular, - ), - trailing: PlatformSwitch( + _buildListTile( + title: "settings.language".tr(), + subtitle: "settings.current_language".tr(), + trailing: CupertinoSwitch( value: EasyLocalization.of(context)?.currentLocale == Locale("en"), onChanged: (value) { @@ -45,17 +39,12 @@ class SettingsPage extends StatelessWidget { } }, ), + hasTopPadding: false, ), - ListTile( - title: Text( - "settings.send_error_log".tr(), - style: bodyBold, - ), - subtitle: Text( - "settings.send_error_log_desc".tr(), - style: bodyRegular, - ), - trailing: PlatformSwitch( + _buildListTile( + title: "settings.send_error_log".tr(), + subtitle: "settings.send_error_log_desc".tr(), + trailing: CupertinoSwitch( value: context.watch().getSendCrashlytics(), onChanged: (value) => context.read().setSendCrashlytics(value), @@ -63,16 +52,10 @@ class SettingsPage extends StatelessWidget { ), Visibility( visible: context.watch().getSendCrashlytics(), - child: ListTile( - title: Text( - "settings.send_anonymously".tr(), - style: bodyBold, - ), - subtitle: Text( - "settings.send_anonymously_desc".tr(), - style: bodyRegular, - ), - trailing: PlatformSwitch( + child: _buildListTile( + title: "settings.send_anonymously".tr(), + subtitle: "settings.send_anonymously_desc".tr(), + trailing: CupertinoSwitch( value: context .watch() .getSendCrashlyticsAnonymously(), @@ -84,20 +67,14 @@ class SettingsPage extends StatelessWidget { ), Visibility( visible: kDebugMode, - child: ListTile( - title: Text( - "settings.throw_test".tr(), - style: bodyBold, - ), - subtitle: Text( - "settings.throw_test_desc".tr(), - style: bodyRegular, - ), + child: _buildListTile( + title: "settings.throw_test".tr(), + subtitle: "settings.throw_test_desc".tr(), onTap: () => throw Exception(), ), ), - ListTile( - title: Text("settings.reset_all".tr(), style: bodyBold), + _buildListTile( + title: "settings.reset_all".tr(), onTap: () { OTLNavigator.pushDialog( context: context, @@ -137,23 +114,29 @@ class SettingsPage extends StatelessWidget { ); }, ), - AboutListTile( - applicationName: "", - applicationIcon: - Image.asset("assets/images/logo.png", height: 48.0), - aboutBoxChildren: [ - Text( - "Online Timeplanner with Lectures Plus @ KAIST", - style: bodyRegular, - ), - IconTextButton( - padding: EdgeInsets.fromLTRB(0, 4, 10, 4), - onTap: () => launchUrl(Uri.parse("mailto:$contactEmail")), - text: contactEmail, - textStyle: - bodyRegular.copyWith(color: OTLColor.pinksMain), - ) - ], + _buildListTile( + title: "settings.about".tr(), + onTap: () => showAboutDialog( + context: context, + applicationName: "", + applicationIcon: + Image.asset("assets/images/logo.png", height: 48.0), + children: [ + Text( + "Online Timeplanner with Lectures Plus @ KAIST", + style: bodyRegular, + ), + IconTextButton( + padding: EdgeInsets.fromLTRB(0, 4, 10, 4), + onTap: () => + launchUrl(Uri.parse("mailto:$contactEmail")), + text: contactEmail, + textStyle: + bodyRegular.copyWith(color: OTLColor.pinksMain), + ) + ], + ), + hasTopPadding: false, ), ], ), @@ -162,4 +145,37 @@ class SettingsPage extends StatelessWidget { ), ); } + + Widget _buildListTile( + {required String title, + String subtitle = '', + Widget? trailing, + void Function()? onTap, + bool hasTopPadding = true}) { + return Padding( + padding: EdgeInsets.only(top: hasTopPadding ? 16 : 0), + child: GestureDetector( + onTap: onTap, + behavior: HitTestBehavior.translucent, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, style: bodyBold), + const SizedBox(height: 4), + Text(subtitle, style: bodyRegular), + ], + ), + ), + if (trailing != null) trailing + ], + ), + ), + ), + ); + } } From bfbae1fe41b58f55c7dd8515b9d28815c149ade1 Mon Sep 17 00:00:00 2001 From: SungyeopJeong Date: Thu, 7 Sep 2023 00:06:21 +0900 Subject: [PATCH 3/5] feat: modify language change UI to dropdown --- assets/translations/en.json | 3 +- assets/translations/ko.json | 3 +- lib/pages/settings_page.dart | 134 +++++++++++++++++++++++++++++++---- 3 files changed, 123 insertions(+), 17 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index b27386ae..0eeeaa29 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -137,7 +137,8 @@ }, "settings": { "language": "Language", - "current_language": "English", + "korean": "Korean", + "english": "English", "send_error_log": "Send error log", "send_error_log_desc": "Automatically collect logs without user reporting", "send_anonymously": "Send anonymously", diff --git a/assets/translations/ko.json b/assets/translations/ko.json index 2186e25c..ac03428b 100644 --- a/assets/translations/ko.json +++ b/assets/translations/ko.json @@ -137,7 +137,8 @@ }, "settings": { "language": "언어", - "current_language": "한국어", + "korean": "한국어", + "english": "영어", "send_error_log": "오류 로그 전송", "send_error_log_desc": "사용자의 제보 없이 자동으로 오류를 수집합니다.", "send_anonymously": "익명으로 전송", diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index b8db0ef2..792d2b46 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -10,12 +10,15 @@ import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter/foundation.dart' show kDebugMode; import 'package:easy_localization/easy_localization.dart'; +import 'package:dropdown_button2/dropdown_button2.dart'; class SettingsPage extends StatelessWidget { final contactEmail = 'otlplus@kaist.ac.kr'; @override Widget build(BuildContext context) { + final isEn = EasyLocalization.of(context)?.currentLocale == Locale('en'); + return OTLScaffold( child: OTLLayout( middle: Text('title.settings'.tr(), style: titleBold), @@ -25,21 +28,122 @@ class SettingsPage extends StatelessWidget { padding: const EdgeInsets.all(16.0), child: Column( children: [ - _buildListTile( - title: "settings.language".tr(), - subtitle: "settings.current_language".tr(), - trailing: CupertinoSwitch( - value: EasyLocalization.of(context)?.currentLocale == - Locale("en"), - onChanged: (value) { - if (value) { - EasyLocalization.of(context)?.setLocale(Locale('en')); - } else { - EasyLocalization.of(context)?.setLocale(Locale('ko')); - } - }, - ), - hasTopPadding: false, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "settings.language".tr(), + style: bodyBold, + ), + DropdownButtonHideUnderline( + child: DropdownButton2( + customButton: Container( + height: 34, + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: OTLColor.pinksLight, + borderRadius: BorderRadius.circular(20), + ), + child: Row( + children: [ + Icon( + Icons.language, + color: OTLColor.pinksMain, + ), + const SizedBox(width: 8), + Text( + isEn + ? "settings.english".tr() + : "settings.korean".tr(), + style: bodyBold.copyWith( + height: 1.2, color: OTLColor.pinksMain), + ) + ], + ), + ), + dropdownStyleData: DropdownStyleData( + direction: DropdownDirection.left, + width: 200, + elevation: 0, + padding: EdgeInsets.zero, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: OTLColor.gray6, + ), + offset: const Offset(0, -6), + ), + menuItemStyleData: MenuItemStyleData( + height: 42, + padding: EdgeInsets.zero, + ), + items: [ + DropdownMenuItem( + value: false, + child: Stack( + alignment: AlignmentDirectional.bottomStart, + children: [ + Container( + height: 42, + child: Row( + children: [ + const SizedBox(width: 16), + !isEn + ? Icon( + Icons.check, + color: OTLColor.grayF, + size: 16, + ) + : const SizedBox(width: 16), + const SizedBox(width: 12), + Text( + "settings.korean".tr(), + style: bodyRegular.copyWith( + color: OTLColor.grayF), + ), + ], + ), + ), + Container( + color: OTLColor.grayF.withOpacity(0.5), + height: 0.5, + ), + ], + ), + ), + DropdownMenuItem( + value: true, + child: Row( + children: [ + const SizedBox(width: 16), + isEn + ? Icon( + Icons.check, + color: OTLColor.grayF, + size: 16, + ) + : const SizedBox(width: 16), + const SizedBox(width: 12), + Text( + "settings.english".tr(), + style: bodyRegular.copyWith( + color: OTLColor.grayF), + ), + ], + ), + ), + ], + onChanged: (value) { + if (value == false) { + EasyLocalization.of(context) + ?.setLocale(Locale('ko')); + } else { + EasyLocalization.of(context) + ?.setLocale(Locale('en')); + } + }, + ), + ), + ], ), _buildListTile( title: "settings.send_error_log".tr(), From e2712fb20ad7e79bbb93017d3f8df59c18e96095 Mon Sep 17 00:00:00 2001 From: SungyeopJeong Date: Thu, 7 Sep 2023 02:09:04 +0900 Subject: [PATCH 4/5] refactor: add dropdown widget --- lib/pages/settings_page.dart | 149 +++++++-------------- lib/widgets/dropdown.dart | 123 ++++++++++++++++++ lib/widgets/hall_of_fame_control.dart | 147 +++++++-------------- lib/widgets/timetable_tabs.dart | 179 ++++++++------------------ 4 files changed, 269 insertions(+), 329 deletions(-) create mode 100644 lib/widgets/dropdown.dart diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index 792d2b46..d0d66e00 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/cupertino.dart'; import 'package:otlplus/constants/color.dart'; import 'package:otlplus/constants/text_styles.dart'; import 'package:otlplus/providers/settings_model.dart'; +import 'package:otlplus/widgets/dropdown.dart'; import 'package:otlplus/widgets/responsive_button.dart'; import 'package:otlplus/utils/navigator.dart'; import 'package:otlplus/widgets/otl_scaffold.dart'; @@ -10,7 +11,6 @@ import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter/foundation.dart' show kDebugMode; import 'package:easy_localization/easy_localization.dart'; -import 'package:dropdown_button2/dropdown_button2.dart'; class SettingsPage extends StatelessWidget { final contactEmail = 'otlplus@kaist.ac.kr'; @@ -35,113 +35,52 @@ class SettingsPage extends StatelessWidget { "settings.language".tr(), style: bodyBold, ), - DropdownButtonHideUnderline( - child: DropdownButton2( - customButton: Container( - height: 34, - padding: const EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - color: OTLColor.pinksLight, - borderRadius: BorderRadius.circular(20), - ), - child: Row( - children: [ - Icon( - Icons.language, - color: OTLColor.pinksMain, - ), - const SizedBox(width: 8), - Text( - isEn - ? "settings.english".tr() - : "settings.korean".tr(), - style: bodyBold.copyWith( - height: 1.2, color: OTLColor.pinksMain), - ) - ], - ), - ), - dropdownStyleData: DropdownStyleData( - direction: DropdownDirection.left, - width: 200, - elevation: 0, - padding: EdgeInsets.zero, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: OTLColor.gray6, - ), - offset: const Offset(0, -6), - ), - menuItemStyleData: MenuItemStyleData( - height: 42, - padding: EdgeInsets.zero, + Dropdown( + customButton: Container( + height: 34, + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: OTLColor.pinksLight, + borderRadius: BorderRadius.circular(20), ), - items: [ - DropdownMenuItem( - value: false, - child: Stack( - alignment: AlignmentDirectional.bottomStart, - children: [ - Container( - height: 42, - child: Row( - children: [ - const SizedBox(width: 16), - !isEn - ? Icon( - Icons.check, - color: OTLColor.grayF, - size: 16, - ) - : const SizedBox(width: 16), - const SizedBox(width: 12), - Text( - "settings.korean".tr(), - style: bodyRegular.copyWith( - color: OTLColor.grayF), - ), - ], - ), - ), - Container( - color: OTLColor.grayF.withOpacity(0.5), - height: 0.5, - ), - ], - ), - ), - DropdownMenuItem( - value: true, - child: Row( - children: [ - const SizedBox(width: 16), - isEn - ? Icon( - Icons.check, - color: OTLColor.grayF, - size: 16, - ) - : const SizedBox(width: 16), - const SizedBox(width: 12), - Text( - "settings.english".tr(), - style: bodyRegular.copyWith( - color: OTLColor.grayF), - ), - ], + child: Row( + children: [ + Icon( + Icons.language, + color: OTLColor.pinksMain, ), - ), - ], - onChanged: (value) { - if (value == false) { - EasyLocalization.of(context) - ?.setLocale(Locale('ko')); - } else { - EasyLocalization.of(context) - ?.setLocale(Locale('en')); - } - }, + const SizedBox(width: 8), + Text( + isEn + ? "settings.english".tr() + : "settings.korean".tr(), + style: bodyBold.copyWith( + height: 1.2, color: OTLColor.pinksMain), + ) + ], + ), ), + items: [ + ItemData( + value: false, + text: "settings.korean".tr(), + icon: !isEn ? Icons.check : null, + ), + ItemData( + value: true, + text: "settings.english".tr(), + icon: isEn ? Icons.check : null, + ), + ], + isIconLeft: true, + offsetY: -6, + onChanged: (value) { + if (value!) { + EasyLocalization.of(context)?.setLocale(Locale('en')); + } else { + EasyLocalization.of(context)?.setLocale(Locale('ko')); + } + }, ), ], ), diff --git a/lib/widgets/dropdown.dart b/lib/widgets/dropdown.dart new file mode 100644 index 00000000..d4afa2c0 --- /dev/null +++ b/lib/widgets/dropdown.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:otlplus/constants/color.dart'; +import 'package:otlplus/constants/text_styles.dart'; + +class ItemData { + final T value; + final String text; + final IconData? icon; + final Color textColor, iconColor; + final bool disabled; + + ItemData({ + required this.value, + required this.text, + this.icon, + this.textColor = OTLColor.grayF, + this.iconColor = OTLColor.grayF, + this.disabled = false, + }); +} + +class Dropdown extends StatelessWidget { + const Dropdown({ + Key? key, + required this.customButton, + required this.items, + this.isIconLeft = false, + this.offsetFromLeft = false, + this.offsetY = -8, + this.hasScrollbar = false, + required this.onChanged, + this.onMenuStateChange, + }) : super(key: key); + + final Widget customButton; + final List> items; + final bool isIconLeft; + final bool offsetFromLeft; + final double offsetY; + final bool hasScrollbar; + final void Function(T?) onChanged; + final void Function(bool)? onMenuStateChange; + + @override + Widget build(BuildContext context) { + return DropdownButtonHideUnderline( + child: DropdownButton2( + customButton: customButton, + dropdownStyleData: DropdownStyleData( + direction: + offsetFromLeft ? DropdownDirection.right : DropdownDirection.left, + width: 200, + maxHeight: 237, + elevation: 0, + padding: EdgeInsets.zero, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: OTLColor.gray6, + ), + offset: Offset(0, offsetY), + scrollbarTheme: hasScrollbar + ? ScrollbarThemeData( + radius: Radius.circular(1.5), + mainAxisMargin: 11.5, + crossAxisMargin: 4.5, + thickness: MaterialStatePropertyAll(3), + thumbColor: MaterialStatePropertyAll(OTLColor.grayF), + ) + : null, + ), + menuItemStyleData: MenuItemStyleData( + height: 42, + padding: EdgeInsets.zero, + ), + items: items.map((itemData) { + final children = [ + Expanded( + child: Text( + itemData.text, + style: bodyRegular.copyWith(color: itemData.textColor), + ), + ), + Padding( + padding: EdgeInsets.only(right: isIconLeft ? 12 : 0), + child: Icon( + itemData.icon, + size: 16, + color: itemData.iconColor, + ), + ), + ]; + return DropdownMenuItem( + value: itemData.value, + child: Stack( + alignment: AlignmentDirectional.bottomStart, + children: [ + Opacity( + opacity: itemData.disabled ? 0.5 : 1, + child: Container( + height: 42, + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: + isIconLeft ? children.reversed.toList() : children, + ), + ), + ), + if (itemData != items.last) + Container( + color: OTLColor.grayF.withOpacity(0.5), + height: 0.5, + ), + ], + ), + ); + }).toList(), + onChanged: onChanged, + onMenuStateChange: onMenuStateChange, + ), + ); + } +} diff --git a/lib/widgets/hall_of_fame_control.dart b/lib/widgets/hall_of_fame_control.dart index d1fbf772..2098de83 100644 --- a/lib/widgets/hall_of_fame_control.dart +++ b/lib/widgets/hall_of_fame_control.dart @@ -1,4 +1,3 @@ -import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:otlplus/constants/color.dart'; @@ -6,6 +5,7 @@ import 'package:otlplus/constants/text_styles.dart'; import 'package:otlplus/models/semester.dart'; import 'package:otlplus/providers/hall_of_fame_model.dart'; import 'package:otlplus/providers/info_model.dart'; +import 'package:otlplus/widgets/dropdown.dart'; import 'package:provider/provider.dart'; class HallOfFameControl extends StatefulWidget { @@ -35,109 +35,58 @@ class _HallOfFameControlState extends State { .toList(); _currentSemester = context.read().semeseter; - return DropdownButtonHideUnderline( - child: DropdownButton2( - onMenuStateChange: (isOpen) => _isOpen = isOpen, - customButton: Container( - height: 34, - padding: EdgeInsets.fromLTRB(16, 0, 8, 0), - decoration: BoxDecoration( - color: OTLColor.grayF, - borderRadius: BorderRadius.circular(100), - ), - child: Row( - children: [ - Text( - _currentSemester == null - ? "common.all".tr() - : "${_currentSemester?.year} ${_currentSemester?.semester == 1 ? 'semester.spring'.tr() : 'semester.fall'.tr()}", - style: evenBodyBold.copyWith( - color: OTLColor.pinksMain, - ), - ), - const SizedBox(width: 2.0), - Icon( - _isOpen ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, - color: OTLColor.pinksMain, - ), - ], - ), - ), - dropdownStyleData: DropdownStyleData( - direction: DropdownDirection.left, - maxHeight: 225, - width: 180, - elevation: 0, - padding: EdgeInsets.zero, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: OTLColor.gray6, - ), - scrollbarTheme: ScrollbarThemeData( - radius: Radius.circular(100), - mainAxisMargin: 8.0, - crossAxisMargin: 4.0, - thickness: MaterialStatePropertyAll(4.0), - thumbColor: MaterialStatePropertyAll(OTLColor.grayF), - ), - offset: const Offset(0, -8), - ), - menuItemStyleData: MenuItemStyleData( - height: 40, - padding: EdgeInsets.zero, + return Dropdown( + customButton: Container( + height: 34, + padding: EdgeInsets.fromLTRB(16, 0, 8, 0), + decoration: BoxDecoration( + color: OTLColor.grayF, + borderRadius: BorderRadius.circular(100), ), - items: [ - DropdownMenuItem( - value: null, - child: buildItem('common.all'.tr(), _currentSemester == null), - ), - ...List.generate( - _targetSemesters.length, - (index) => DropdownMenuItem( - value: _targetSemesters[index], - child: buildItem( - "${_targetSemesters[index].year} ${_targetSemesters[index].semester == 1 ? 'semester.spring'.tr() : 'semester.fall'.tr()}", - _currentSemester == _targetSemesters[index], - ), - ), - ).reversed - ], - onChanged: (value) { - setState(() { - context.read().setSemester(value); - context.read().clear(); - }); - }, - ), - ); - } -} - -Widget buildItem(String text, bool selected) { - return Stack( - alignment: AlignmentDirectional.bottomStart, - children: [ - Container( - height: 40, - alignment: Alignment.center, - padding: EdgeInsets.symmetric(horizontal: 16), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - text, - style: bodyRegular.copyWith(color: OTLColor.grayF), + _currentSemester == null + ? "common.all".tr() + : "${_currentSemester?.year} ${_currentSemester?.semester == 1 ? 'semester.spring'.tr() : 'semester.fall'.tr()}", + style: evenBodyBold.copyWith( + color: OTLColor.pinksMain, + ), + ), + const SizedBox(width: 2.0), + Icon( + _isOpen ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, + color: OTLColor.pinksMain, ), - selected - ? Icon(Icons.check, color: OTLColor.grayF) - : SizedBox(width: 24.0), ], ), ), - Container( - color: OTLColor.grayF.withOpacity(0.5), - height: 0.5, - ), - ], - ); -} + items: [ + ItemData( + value: null, + text: 'common.all'.tr(), + icon: _currentSemester == null ? Icons.check : null, + ), + ...List.generate( + _targetSemesters.length, + (index) => ItemData( + value: _targetSemesters[index], + text: + "${_targetSemesters[index].year} ${_targetSemesters[index].semester == 1 ? 'semester.spring'.tr() : 'semester.fall'.tr()}", + icon: _currentSemester == _targetSemesters[index] + ? Icons.check + : null, + ), + ).reversed, + ], + hasScrollbar: true, + onChanged: (value) { + setState(() { + context.read().setSemester(value); + context.read().clear(); + }); + }, + onMenuStateChange: (isOpen) => setState(() => _isOpen = isOpen), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/timetable_tabs.dart b/lib/widgets/timetable_tabs.dart index 1ec83be1..f3798c32 100644 --- a/lib/widgets/timetable_tabs.dart +++ b/lib/widgets/timetable_tabs.dart @@ -1,9 +1,9 @@ -import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:otlplus/constants/color.dart'; import 'package:otlplus/constants/text_styles.dart'; import 'package:otlplus/constants/url.dart'; +import 'package:otlplus/widgets/dropdown.dart'; class TimetableTabs extends StatefulWidget { final int index; @@ -81,65 +81,63 @@ class _TimetableTabsState extends State { bool canDelete = widget.length > 2 && i != 0; return Padding( padding: const EdgeInsets.only(right: 8.0), - child: DropdownButtonHideUnderline( - child: DropdownButton2( - customButton: Container( - height: 28, - padding: EdgeInsets.fromLTRB(12, 0, 8, 0), - decoration: BoxDecoration( - color: OTLColor.pinksMain, - borderRadius: BorderRadius.circular(100), - ), - child: Row( - children: [ - text, - const SizedBox(width: 6), - Icon( - Icons.more_vert, - color: OTLColor.grayF, - size: 16, - ), - ], - ), + child: Dropdown( + customButton: Container( + height: 28, + padding: EdgeInsets.fromLTRB(12, 0, 8, 0), + decoration: BoxDecoration( + color: OTLColor.pinksMain, + borderRadius: BorderRadius.circular(100), ), - items: [ - ...MenuItems.items.map( - (item) => DropdownMenuItem( - value: item, - child: MenuItems.buildItem( - item, !(canDelete) && item == MenuItems.items.last), + child: Row( + children: [ + text, + const SizedBox(width: 6), + Icon( + Icons.more_vert, + color: OTLColor.grayF, + size: 16, ), - ), - if (canDelete) - DropdownMenuItem( - value: MenuItems.delete, - child: MenuItems.buildItem(MenuItems.delete, true), - ), - ], - onChanged: (value) { - if (value == MenuItems.copy) widget.onCopyTap(); - if (value == MenuItems.exportToImg) - widget.onExportTap(ShareType.image); - if (value == MenuItems.exportToCal) - widget.onExportTap(ShareType.ical); - // if (value == MenuItems.syllabus) Pass - if (value == MenuItems.delete) widget.onDeleteTap(); - }, - dropdownStyleData: DropdownStyleData( - width: 200, - elevation: 0, - padding: EdgeInsets.zero, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: OTLColor.gray6, - ), - offset: const Offset(0, -8), - ), - menuItemStyleData: MenuItemStyleData( - height: 40, - padding: EdgeInsets.zero, + ], ), ), + items: [ + ItemData( + value: 0, + text: 'timetable.tab_menu.copy'.tr(), + icon: Icons.copy, + ), + ItemData( + value: 1, + text: 'timetable.tab_menu.export_img'.tr(), + icon: Icons.image_outlined, + ), + ItemData( + value: 2, + text: 'timetable.tab_menu.export_cal'.tr(), + icon: Icons.calendar_today_outlined, + ), + ItemData( + value: 3, + text: 'timetable.tab_menu.delete'.tr(), + icon: Icons.delete_outlined, + textColor: OTLColor.red, + disabled: !canDelete, + ), + /*ItemData( + value: 4, + text: 'timetable.tab_menu.syllabus'.tr(), + icon: Icons.sticky_note_2_outlined, + ),*/ + ], + offsetFromLeft: true, + onChanged: (value) { + if (value == 0) widget.onCopyTap(); + if (value == 1) widget.onExportTap(ShareType.image); + if (value == 2) widget.onExportTap(ShareType.ical); + if (value == 3 && canDelete) widget.onDeleteTap(); + // if (value == 4) Pass + }, ), ); } @@ -167,72 +165,3 @@ class _TimetableTabsState extends State { ); } } - -class MenuItem { - const MenuItem({ - required this.text, - required this.icon, - }); - - final String text; - final IconData icon; -} - -abstract class MenuItems { - static final List items = [ - copy, - exportToImg, - exportToCal, - //syllabus, - ]; - - static final copy = - MenuItem(text: 'timetable.tab_menu.copy'.tr(), icon: Icons.copy); - static final exportToImg = MenuItem( - text: 'timetable.tab_menu.export_img'.tr(), icon: Icons.image_outlined); - static final exportToCal = MenuItem( - text: 'timetable.tab_menu.export_cal'.tr(), - icon: Icons.calendar_today_outlined); - static final syllabus = MenuItem( - text: 'timetable.tab_menu.syllabus'.tr(), - icon: Icons.sticky_note_2_outlined); - static final delete = MenuItem( - text: 'timetable.tab_menu.delete'.tr(), icon: Icons.delete_outlined); - - static Widget buildItem(MenuItem item, bool isLast) { - Color color = item == delete ? OTLColor.red : OTLColor.grayF; - return Stack( - alignment: AlignmentDirectional.bottomStart, - children: [ - Container( - height: 40, - alignment: Alignment.center, - padding: EdgeInsets.symmetric(horizontal: 16), - child: Row( - children: [ - Expanded( - child: Text( - item.text, - style: bodyRegular.copyWith( - color: color, - overflow: TextOverflow.ellipsis, - ), - ), - ), - Icon( - item.icon, - color: color, - size: 16, - ), - ], - ), - ), - if (!isLast) - Container( - color: OTLColor.grayF.withOpacity(0.5), - height: 0.5, - ), - ], - ); - } -} From c2e0a8528173c1972aaf39e35607a234d2d66a9b Mon Sep 17 00:00:00 2001 From: SungyeopJeong Date: Thu, 7 Sep 2023 02:30:56 +0900 Subject: [PATCH 5/5] chore: format code --- lib/widgets/hall_of_fame_control.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/hall_of_fame_control.dart b/lib/widgets/hall_of_fame_control.dart index 2098de83..db4c66af 100644 --- a/lib/widgets/hall_of_fame_control.dart +++ b/lib/widgets/hall_of_fame_control.dart @@ -89,4 +89,4 @@ class _HallOfFameControlState extends State { onMenuStateChange: (isOpen) => setState(() => _isOpen = isOpen), ); } -} \ No newline at end of file +}