From b3d89406432c0df6ab295600ab9d7f1325ac989e Mon Sep 17 00:00:00 2001 From: SungyeopJeong Date: Sat, 12 Aug 2023 18:54:56 +0900 Subject: [PATCH 1/4] refactor: add delete dialog --- lib/pages/timetable_page.dart | 84 ++++------------------------------ lib/widgets/delete_dialog.dart | 83 +++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 74 deletions(-) create mode 100644 lib/widgets/delete_dialog.dart diff --git a/lib/pages/timetable_page.dart b/lib/pages/timetable_page.dart index 26fa50b0..5d646f33 100644 --- a/lib/pages/timetable_page.dart +++ b/lib/pages/timetable_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:otlplus/utils/build_page_route.dart'; import 'package:otlplus/providers/lecture_search_model.dart'; import 'package:otlplus/utils/responsive_button.dart'; +import 'package:otlplus/widgets/delete_dialog.dart'; import 'package:otlplus/widgets/lecture_search.dart'; import 'package:otlplus/widgets/map_view.dart'; import 'package:provider/provider.dart'; @@ -254,8 +255,15 @@ class _TimetablePageState extends State { barrierDismissible: true, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, - pageBuilder: (context, _, __) => - _buildDeleteDialog(context, timetableModel.selectedIndex), + pageBuilder: (context, _, __) => DeleteDialog( + text: 'timetable.ask_delete_tab'.tr(args: [ + 'timetable.tab' + .tr(args: [timetableModel.selectedIndex.toString()]) + ]), + onDelete: () { + context.read().deleteTimetable(); + }, + ), ); }, onExportTap: (type) { @@ -265,76 +273,4 @@ class _TimetablePageState extends State { }, ); } - - Widget _buildDeleteDialog(BuildContext context, int i) { - return Center( - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Material( - child: IntrinsicWidth( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(16, 19, 16, 20), - alignment: Alignment.center, - color: Colors.white, - child: Text( - 'timetable.ask_delete_tab'.tr(args: [ - 'timetable.tab'.tr(args: [i.toString()]) - ]), - style: TextStyle( - fontSize: 12, - ), - ), - ), - Row( - children: [ - Expanded( - child: GestureDetector( - onTap: () => Navigator.pop(context), - child: Container( - height: 40, - alignment: Alignment.center, - color: OTLColor.grayE, - child: Text( - 'common.cancel'.tr(), - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w700, - ), - ), - ), - ), - ), - Expanded( - child: GestureDetector( - onTap: () { - context.read().deleteTimetable(); - Navigator.pop(context); - }, - child: Container( - height: 40, - alignment: Alignment.center, - color: OTLColor.pinksMain, - child: Text( - 'common.delete'.tr(), - style: TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w700, - ), - ), - ), - ), - ), - ], - ) - ], - ), - ), - ), - ), - ); - } } diff --git a/lib/widgets/delete_dialog.dart b/lib/widgets/delete_dialog.dart new file mode 100644 index 00000000..b5fd85db --- /dev/null +++ b/lib/widgets/delete_dialog.dart @@ -0,0 +1,83 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:otlplus/constants/color.dart'; + +class DeleteDialog extends StatelessWidget { + const DeleteDialog({Key? key, required this.text, this.onDelete}) + : super(key: key); + final String text; + final void Function()? onDelete; + + @override + Widget build(BuildContext context) { + return Center( + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Material( + child: IntrinsicWidth( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.fromLTRB(16, 19, 16, 20), + alignment: Alignment.center, + color: Colors.white, + child: Text( + text, + style: TextStyle( + fontSize: 12, + ), + ), + ), + Row( + children: [ + _buildButton( + () => Navigator.pop(context), + text: 'common.cancel'.tr(), + buttonColor: OTLColor.grayE, + ), + _buildButton( + () { + if (onDelete != null) onDelete!(); + Navigator.pop(context); + }, + text: 'common.delete'.tr(), + buttonColor: OTLColor.pinksMain, + textColor: Colors.white, + ), + ], + ) + ], + ), + ), + ), + ), + ); + } + + Widget _buildButton( + void Function()? onTap, { + required String text, + required Color buttonColor, + Color? textColor, + }) { + return Expanded( + child: GestureDetector( + onTap: onTap, + child: Container( + height: 40, + alignment: Alignment.center, + color: buttonColor, + child: Text( + text, + style: TextStyle( + color: textColor, + fontSize: 12, + fontWeight: FontWeight.w700, + ), + ), + ), + ), + ); + } +} From b0dec43c9983a64ec6a68a51a9cfb26b3f50575a Mon Sep 17 00:00:00 2001 From: SungyeopJeong Date: Sat, 12 Aug 2023 19:35:10 +0900 Subject: [PATCH 2/4] feat: add delete account UI --- assets/translations/en.json | 4 ++- assets/translations/ko.json | 4 ++- lib/pages/user_page.dart | 60 ++++++++++++++++++++++++++--------- lib/providers/info_model.dart | 5 +++ 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index 98263701..b2d3b8fa 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -121,7 +121,9 @@ "major": "Major", "my_review": "My Reviews", "liked_review": "Liked Reviews", - "logout": "Logout" + "logout": "Logout", + "delete_account": "Delete Account", + "ask_delete_account": "Are you sure you want to delete your account?" }, "settings": { "send_error_log": "Send error log", diff --git a/assets/translations/ko.json b/assets/translations/ko.json index d209d355..c072c20f 100644 --- a/assets/translations/ko.json +++ b/assets/translations/ko.json @@ -121,7 +121,9 @@ "major": "전공", "my_review": "내가 들은 과목", "liked_review": "좋아요한 후기", - "logout": "로그아웃" + "logout": "로그아웃", + "delete_account": "계정 삭제", + "ask_delete_account": "계정을 정말 삭제하시겠습니까?" }, "settings": { "send_error_log": "오류 로그 전송", diff --git a/lib/pages/user_page.dart b/lib/pages/user_page.dart index 119f097a..2d02d83c 100644 --- a/lib/pages/user_page.dart +++ b/lib/pages/user_page.dart @@ -5,6 +5,7 @@ import 'package:otlplus/providers/auth_model.dart'; import 'package:otlplus/utils/build_app_bar.dart'; import 'package:otlplus/utils/build_page_route.dart'; import 'package:otlplus/utils/responsive_button.dart'; +import 'package:otlplus/widgets/delete_dialog.dart'; import 'package:provider/provider.dart'; import 'package:otlplus/constants/color.dart'; import 'package:otlplus/providers/info_model.dart'; @@ -57,21 +58,35 @@ class UserPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16.0), child: _buildDivider(), ), - Align( - alignment: Alignment.centerLeft, - child: IconTextButton( - icon: 'assets/icons/logout.svg', - onTap: () { - context.read().logout(); - context.read().logout(); - Navigator.pop(context); - }, - text: 'user.logout'.tr(), - color: OTLColor.pinksMain, - textStyle: bodyBold, - spaceBetween: 8.0, - padding: EdgeInsets.symmetric(horizontal: 16.0), - ), + _buildAccount( + 'assets/icons/logout.svg', + () { + context.read().logout(); + context.read().logout(); + Navigator.pop(context); + }, + 'user.logout'.tr(), + ), + _buildAccount( + Icons.highlight_off, + () async { + showGeneralDialog( + context: context, + barrierColor: Colors.black.withOpacity(0.2), + barrierDismissible: true, + barrierLabel: MaterialLocalizations.of(context) + .modalBarrierDismissLabel, + pageBuilder: (context, _, __) => DeleteDialog( + text: 'user.ask_delete_account'.tr(), + onDelete: () { + context.read().logout(); + context.read().deleteAccount(); + Navigator.pop(context); + }, + ), + ); + }, + 'user.delete_account'.tr(), ), ], ), @@ -150,4 +165,19 @@ class UserPage extends StatelessWidget { onTap: onTap, ); } + + Widget _buildAccount(dynamic icon, void Function()? onTap, String? text) { + return Align( + alignment: Alignment.centerLeft, + child: IconTextButton( + icon: icon, + onTap: onTap, + text: text, + color: OTLColor.pinksMain, + textStyle: bodyBold, + spaceBetween: 8.0, + padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 6.0), + ), + ); + } } diff --git a/lib/providers/info_model.dart b/lib/providers/info_model.dart index 417fa749..d4e0c289 100644 --- a/lib/providers/info_model.dart +++ b/lib/providers/info_model.dart @@ -120,4 +120,9 @@ class InfoModel extends ChangeNotifier { return schedules.firstWhere((e) => e!["time"].isAfter(now), orElse: () => null); } + + void deleteAccount() { + _hasData = false; + notifyListeners(); + } } From fbb684c040459df03b574221d1d9a7b439e959df Mon Sep 17 00:00:00 2001 From: SungyeopJeong Date: Tue, 15 Aug 2023 14:47:43 +0900 Subject: [PATCH 3/4] feat: add delete account --- assets/translations/en.json | 7 +++++-- assets/translations/ko.json | 7 +++++-- lib/pages/login_page.dart | 35 +++++++++++++++++++++++++++++++++++ lib/providers/info_model.dart | 22 ++++++++++++---------- 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index b2d3b8fa..15de115c 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -17,7 +17,8 @@ "unselect_all": "Unselect All", "no_info": "No information", "all_selected": "All Selected", - "num_selected": " Selected" + "num_selected": " Selected", + "close": "Close" }, "semester": { "spring": "Spring", @@ -123,7 +124,9 @@ "liked_review": "Liked Reviews", "logout": "Logout", "delete_account": "Delete Account", - "ask_delete_account": "Are you sure you want to delete your account?" + "ask_delete_account": "Are you sure you want to delete your account?", + "account_deleted": "Account Deleted", + "deleted_account": "This is the deleted account." }, "settings": { "send_error_log": "Send error log", diff --git a/assets/translations/ko.json b/assets/translations/ko.json index c072c20f..b17b4968 100644 --- a/assets/translations/ko.json +++ b/assets/translations/ko.json @@ -17,7 +17,8 @@ "unselect_all": "모두 해제", "no_info": "정보 없음", "all_selected": "전체 선택됨", - "num_selected": "개 선택됨" + "num_selected": "개 선택됨", + "close": "닫기" }, "semester": { "spring": "봄", @@ -123,7 +124,9 @@ "liked_review": "좋아요한 후기", "logout": "로그아웃", "delete_account": "계정 삭제", - "ask_delete_account": "계정을 정말 삭제하시겠습니까?" + "ask_delete_account": "계정을 정말 삭제하시겠습니까?", + "account_deleted": "계정 삭제됨", + "deleted_account": "삭제된 계정입니다." }, "settings": { "send_error_log": "오류 로그 전송", diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index 74901ca8..975c94b3 100644 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -1,9 +1,14 @@ import 'dart:io'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:otlplus/constants/color.dart'; +import 'package:otlplus/utils/responsive_button.dart'; import 'package:provider/provider.dart'; import 'package:otlplus/constants/url.dart'; import 'package:otlplus/providers/auth_model.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:webview_flutter/webview_flutter.dart'; class LoginPage extends StatefulWidget { @@ -16,6 +21,36 @@ class LoginPage extends StatefulWidget { class _LoginPageState extends State { bool _isVisible = true; + @override + void initState() { + super.initState(); + + WidgetsBinding.instance.addPostFrameCallback( + (_) async { + if (!((await SharedPreferences.getInstance()).getBool('hasAccount') ?? + true)) { + await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('user.account_deleted'.tr()), + content: Text('user.deleted_account'.tr()), + actions: [ + IconTextButton( + padding: EdgeInsets.all(12), + text: 'common.close'.tr(), + color: OTLColor.pinksMain, + onTap: () { + SystemNavigator.pop(); + }, + ), + ], + ), + ); + } + }, + ); + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/providers/info_model.dart b/lib/providers/info_model.dart index d4e0c289..711acc56 100644 --- a/lib/providers/info_model.dart +++ b/lib/providers/info_model.dart @@ -4,6 +4,7 @@ import 'package:otlplus/dio_provider.dart'; import 'package:otlplus/extensions/semester.dart'; import 'package:otlplus/models/semester.dart'; import 'package:otlplus/models/user.dart'; +import 'package:shared_preferences/shared_preferences.dart'; const USED_SCHEDULE_FIELDS = [ "beginning", @@ -77,16 +78,15 @@ class InfoModel extends ChangeNotifier { } Future getInfo() async { - // try { - _semesters = await getSemesters(); - _years = _semesters.map((semester) => semester.year).toSet(); - _user = await getUser(); - _currentSchedule = getCurrentSchedule(); - _hasData = true; + if ((await SharedPreferences.getInstance()).getBool('hasAccount') ?? + true) { + _semesters = await getSemesters(); + _years = _semesters.map((semester) => semester.year).toSet(); + _user = await getUser(); + _currentSchedule = getCurrentSchedule(); + _hasData = true; + } notifyListeners(); - // } catch (exception) { - // print(exception); - // } } Future> getSemesters() async { @@ -121,7 +121,9 @@ class InfoModel extends ChangeNotifier { orElse: () => null); } - void deleteAccount() { + Future deleteAccount() async { + final pref = await SharedPreferences.getInstance(); + pref.setBool('hasAccount', false); _hasData = false; notifyListeners(); } From 2aa4c35492e66881f9d71c8144558f15a056b1e6 Mon Sep 17 00:00:00 2001 From: Seungbin Oh Date: Thu, 17 Aug 2023 10:18:25 +0900 Subject: [PATCH 4/4] feat: show delete account button only in iOS --- lib/pages/user_page.dart | 45 +++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/lib/pages/user_page.dart b/lib/pages/user_page.dart index 2d02d83c..6febee39 100644 --- a/lib/pages/user_page.dart +++ b/lib/pages/user_page.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:otlplus/constants/text_styles.dart'; @@ -67,27 +69,28 @@ class UserPage extends StatelessWidget { }, 'user.logout'.tr(), ), - _buildAccount( - Icons.highlight_off, - () async { - showGeneralDialog( - context: context, - barrierColor: Colors.black.withOpacity(0.2), - barrierDismissible: true, - barrierLabel: MaterialLocalizations.of(context) - .modalBarrierDismissLabel, - pageBuilder: (context, _, __) => DeleteDialog( - text: 'user.ask_delete_account'.tr(), - onDelete: () { - context.read().logout(); - context.read().deleteAccount(); - Navigator.pop(context); - }, - ), - ); - }, - 'user.delete_account'.tr(), - ), + if (Platform.isIOS) + _buildAccount( + Icons.highlight_off, + () async { + showGeneralDialog( + context: context, + barrierColor: Colors.black.withOpacity(0.2), + barrierDismissible: true, + barrierLabel: MaterialLocalizations.of(context) + .modalBarrierDismissLabel, + pageBuilder: (context, _, __) => DeleteDialog( + text: 'user.ask_delete_account'.tr(), + onDelete: () { + context.read().logout(); + context.read().deleteAccount(); + Navigator.pop(context); + }, + ), + ); + }, + 'user.delete_account'.tr(), + ), ], ), ),