diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index cfb7a6d..26d698e 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -13,6 +13,7 @@ "btn.ok": "Ok", "btn.continue":"Continue", "btn.previous":"Previous", + "btn.delete":"Continue to account deletion", "feet":"Feet", "inch":"Inch", "back.button_confirm":"Are you sure you want to continue without submitting changes?", @@ -170,6 +171,8 @@ "profile.edit.currency.title":"Preferred Currency", "profile.name": "Name", "profile.phone": "Phone", + "profile.delete.title": "Delete Account", + "delete.confirm.label":"Are you sure to delete your account?", "profile.language": "Languages", "profile.logout": "logout", "profile.currency":"Preferred currency", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index b6e416b..f2ce5d6 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -12,6 +12,7 @@ "btn.ok": "အိုကေ", "btn.continue":"ဆက်ရန်", "btn.previous":"နောက်သို့", + "btn.delete":"အကောင့်ဖျက်ခြင်းကို ဆက်လက်လုပ်ဆောင်မည်", "feet":"ပေ", "inch":"လက်မ", "back.button_confirm":"Are you sure you want to continue without submitting changes?", @@ -171,6 +172,8 @@ "profile.edit.currency.title":"နှစ်သက်သော ငွေအမျိုးအစား", "profile.name":"နာမည်", "profile.phone": "ဖုန်းနံပါတ်", + "profile.delete.title": "အကောင့်ဖျက်ခြင်း", + "delete.confirm.label":"သင့်အကောင့်ကို ဖျက်ရန် သေချာပြီလား?", "profile.language": "ဘာသာစကားများ", "profile.logout": "အကောင့်ထွက်ရန်", "profile.currency":"နှစ်သက်သော ငွေအမျိုးအစား", diff --git a/lib/data/provider/auth_fb.dart b/lib/data/provider/auth_fb.dart index 7e79a04..fc2110f 100644 --- a/lib/data/provider/auth_fb.dart +++ b/lib/data/provider/auth_fb.dart @@ -202,6 +202,10 @@ class AuthFb { payload: {"preferred_currency": currency}, token: await getToken()); } + Future deleteAccount() async { + return await requestAPI("/accounts", "DELETE", token: await getToken()); + } + Stream settings() async* { Stream snapshot = FirebaseFirestore.instance .collection(config_collection) diff --git a/lib/data/services/auth_imp.dart b/lib/data/services/auth_imp.dart index e3d1b11..def1606 100644 --- a/lib/data/services/auth_imp.dart +++ b/lib/data/services/auth_imp.dart @@ -69,4 +69,9 @@ class AuthServiceImp implements AuthService { Future signoutStart() { return authFb.signoutStart(); } + + @override + Future deleteAccount() { + return authFb.deleteAccount(); + } } diff --git a/lib/data/services/auth_service.dart b/lib/data/services/auth_service.dart index ceba0bf..4a6c6ad 100644 --- a/lib/data/services/auth_service.dart +++ b/lib/data/services/auth_service.dart @@ -14,4 +14,5 @@ abstract class AuthService { Future hasInvite(); Stream getUserStream(); Stream getSetting(); + Future deleteAccount(); } diff --git a/lib/domain/entities/setting.dart b/lib/domain/entities/setting.dart index b9d303c..1c553d3 100644 --- a/lib/domain/entities/setting.dart +++ b/lib/domain/entities/setting.dart @@ -23,6 +23,8 @@ class Setting { final String? termsMm; String? about; String? courierWebsite; + String? deactivateTextEn; + String? deactivateTextMm; List shipmentTypes; @@ -40,7 +42,9 @@ class Setting { this.termsMm, this.about, this.shipmentTypes = const [], - this.courierWebsite}); + this.courierWebsite, + this.deactivateTextEn, + this.deactivateTextMm}); factory Setting.fromMap(Map map) { return Setting( @@ -58,6 +62,8 @@ class Setting { termsMm: map['terms_mm_markdown'], shipmentTypes: List.from(map['shipment_types']), courierWebsite: map['courier_website'], + deactivateTextEn: map['deactivate_text_en']??"", + deactivateTextMm: map['deactivate_text_mm']??"" ); } diff --git a/lib/pages/carton/carton_filter.dart b/lib/pages/carton/carton_filter.dart index 8396502..7d45c34 100644 --- a/lib/pages/carton/carton_filter.dart +++ b/lib/pages/carton/carton_filter.dart @@ -108,7 +108,7 @@ class _CartonFilterState extends State { Future _loadMoreConsignee() async { if (_isLoadMoreConsignee) return; var model = context.read(); - if (model.reachEnd || model.ended) return; + if (model.ended) return; setState(() { _isLoadMoreConsignee = true; }); @@ -141,7 +141,7 @@ class _CartonFilterState extends State { Future _loadMoreSender() async { if (_isLoadMoreSender) return; var model = context.read(); - if (model.reachEnd || model.ended) return; + if (model.ended) return; setState(() { _isLoadMoreSender = true; }); diff --git a/lib/pages/carton/model/consignee_selection_model.dart b/lib/pages/carton/model/consignee_selection_model.dart index db136f8..770823c 100644 --- a/lib/pages/carton/model/consignee_selection_model.dart +++ b/lib/pages/carton/model/consignee_selection_model.dart @@ -1,23 +1,28 @@ import 'dart:async'; +import 'dart:convert'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:fcs/config.dart'; import 'package:logging/logging.dart'; import '../../../domain/constants.dart'; import '../../../domain/entities/user.dart'; +import '../../../helpers/api_helper.dart'; +import '../../../helpers/firebase_helper.dart'; import '../../main/model/base_model.dart'; class ConsigneeSelectionModel extends BaseModel { final log = Logger("ConsigneeSearchModel"); // for search String query = ""; - int offset = 0; - bool reachEnd = false; List _consignees = []; List get getConsginees { var users = new List.from(_consignees); - return users..insert(0, User(id: all, name: "All")); + if (query == "") { + return users..insert(0, User(id: all, name: "All")); + } + return users; } bool isLoading = false; @@ -30,8 +35,6 @@ class ConsigneeSelectionModel extends BaseModel { search(String term, {bool imm = false}) async { query = term; _consignees.clear(); - offset = 0; - reachEnd = false; t?.cancel(); t = Timer(Duration(milliseconds: imm ? 0 : 800), () async { await loadMoreSearch(term: term); @@ -43,35 +46,26 @@ class ConsigneeSelectionModel extends BaseModel { await _refresh(); return; } - // int rowPerPage = 21; - // List list = []; - // SearchPara searchPara = SearchPara(filters: [], term: term); - // isLoading = true; + var bytes = utf8.encode(term); + var base64Str = base64.encode(bytes); + HtmlEscape htmlEscape = const HtmlEscape(); + String escapeSender = htmlEscape.convert(base64Str); - // var path = - // "/search/$cartons_collection/${searchPara.escapeTerm}/$rowPerPage/$offset/${searchPara.escapeFilters}"; + int rowPerPage = 20; + List list = []; - // var result = await requestAPI(path, "GET", - // token: await getToken(), url: Config.instance.searchURL); + var result = await requestAPI( + "/api/fts/$user_collection/$escapeSender/$rowPerPage", "GET", + url: Config.instance.reportURL, token: await getToken()); - // if (result != null) { - // for (var row in result) { - // var item = ArtistExt.fromMapForSearch(row); - // list.add(item); - // } - // } + if (result != null) { + for (var row in result) { + var item = User.fromJson(row); + list.add(item); + } + } - // for (var p in list) { - // selectedArtistList.contains(p) - // ? p.isSelected = true - // : p.isSelected = false; - // } - - // artists.addAll(list); - // offset += rowPerPage; - // if (list.length < rowPerPage) { - // reachEnd = true; - // } + _consignees = List.from(list); notifyListeners(); } diff --git a/lib/pages/carton/model/sender_selection_model.dart b/lib/pages/carton/model/sender_selection_model.dart index e919e11..0b7420d 100644 --- a/lib/pages/carton/model/sender_selection_model.dart +++ b/lib/pages/carton/model/sender_selection_model.dart @@ -1,23 +1,28 @@ import 'dart:async'; +import 'dart:convert'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:logging/logging.dart'; +import '../../../config.dart'; import '../../../domain/constants.dart'; import '../../../domain/entities/user.dart'; +import '../../../helpers/api_helper.dart'; +import '../../../helpers/firebase_helper.dart'; import '../../main/model/base_model.dart'; class SenderSelectionModel extends BaseModel { final log = Logger("SenderSelectionModel"); // for search String query = ""; - int offset = 0; - bool reachEnd = false; List _senders = []; List get getSenders { var users = new List.from(_senders); - return users..insert(0, User(id: all, name: "All")); + if (query == "") { + return users..insert(0, User(id: all, name: "All")); + } + return users; } bool isLoading = false; @@ -30,8 +35,6 @@ class SenderSelectionModel extends BaseModel { search(String term, {bool imm = false}) async { query = term; _senders.clear(); - offset = 0; - reachEnd = false; t?.cancel(); t = Timer(Duration(milliseconds: imm ? 0 : 800), () async { await loadMoreSearch(term: term); @@ -44,31 +47,28 @@ class SenderSelectionModel extends BaseModel { return; } - // var bytes = utf8.encode(term); - // var base64Str = base64.encode(bytes); - // HtmlEscape htmlEscape = const HtmlEscape(); - // String escapeSender = htmlEscape.convert(base64Str); + var bytes = utf8.encode(term); + var base64Str = base64.encode(bytes); + HtmlEscape htmlEscape = const HtmlEscape(); + String escapeSender = htmlEscape.convert(base64Str); - // int rowPerPage = 20; - // List list = []; + int rowPerPage = 20; + List list = []; - // var result = await requestAPI( - // "/api/fts/$user_collection/$escapeSender/$rowPerPage", "GET", - // url: Config.instance.reportURL, token: await getToken()); + var result = await requestAPI( + "/api/fts/$user_collection/$escapeSender/$rowPerPage", "GET", + url: Config.instance.reportURL, token: await getToken()); - // if (result != null) { - // for (var row in result) { - // var item = User.fromJson(row); - // list.add(item); - // } - // } + if (result != null) { + for (var row in result) { + var item = User.fromJson(row); + list.add(item); + } + } - // _senders.addAll(list); - // offset += rowPerPage; - // if (list.length < rowPerPage) { - // reachEnd = true; - // } - // notifyListeners(); + _senders = List.from(list); + + notifyListeners(); } addDefaultSenders() async { diff --git a/lib/pages/carton_search/carton_list_row.dart b/lib/pages/carton_search/carton_list_row.dart index c816ea3..10cf69a 100644 --- a/lib/pages/carton_search/carton_list_row.dart +++ b/lib/pages/carton_search/carton_list_row.dart @@ -1,8 +1,10 @@ import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/helpers/theme.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; +import '../carton/print_qr_code_page.dart'; import 'carton_search.dart'; class CartonListRow extends StatelessWidget { @@ -69,7 +71,14 @@ class CartonListRow extends StatelessWidget { ), const SizedBox(width: 15), IconButton( - onPressed: () {}, + onPressed: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + PrintQrCodePage(carton: carton)), + ); + }, icon: Icon(AntDesign.qrcode, color: Colors.black)) ], diff --git a/lib/pages/carton_search/carton_search.dart b/lib/pages/carton_search/carton_search.dart index 10d39c3..eeecc2c 100644 --- a/lib/pages/carton_search/carton_search.dart +++ b/lib/pages/carton_search/carton_search.dart @@ -81,6 +81,7 @@ class PartSearchDelegate extends SearchDelegate { child: Text( "No result found", textAlign: TextAlign.center, + style: TextStyle(color: Colors.black), ), ), ); diff --git a/lib/pages/carton_size/carton_size_editor.dart b/lib/pages/carton_size/carton_size_editor.dart index f615a35..9fb31e0 100644 --- a/lib/pages/carton_size/carton_size_editor.dart +++ b/lib/pages/carton_size/carton_size_editor.dart @@ -62,6 +62,7 @@ class _CartonSizeEditorState extends State { final lengthBox = LengthPicker( controller: _lengthController, lableKey: "box.length", + displayFeet: true, ); final widthBox = LengthPicker( controller: _widthController, diff --git a/lib/pages/main/model/main_model.dart b/lib/pages/main/model/main_model.dart index c76dc0f..b541704 100644 --- a/lib/pages/main/model/main_model.dart +++ b/lib/pages/main/model/main_model.dart @@ -192,4 +192,8 @@ class MainModel extends ChangeNotifier { await Services.instance.authService.updatePreferredCurrency(currency); notifyListeners(); } + + Future deleteAccount() async { + return await Services.instance.authService.deleteAccount(); + } } diff --git a/lib/pages/package_search/package_search.dart b/lib/pages/package_search/package_search.dart index 297f183..b3e6b85 100644 --- a/lib/pages/package_search/package_search.dart +++ b/lib/pages/package_search/package_search.dart @@ -80,6 +80,7 @@ class PackageSearchDelegate extends SearchDelegate { child: Text( "No result found", textAlign: TextAlign.center, + style: TextStyle(color: Colors.black), ), ), ); diff --git a/lib/pages/pickup_search/pickup_search.dart b/lib/pages/pickup_search/pickup_search.dart index cbae4ee..a167ce2 100644 --- a/lib/pages/pickup_search/pickup_search.dart +++ b/lib/pages/pickup_search/pickup_search.dart @@ -81,6 +81,7 @@ class PackageSearchDelegate extends SearchDelegate { child: Text( "No result found", textAlign: TextAlign.center, + style: TextStyle(color: Colors.black), ), ), ); diff --git a/lib/pages/profile/account_delection_page.dart b/lib/pages/profile/account_delection_page.dart new file mode 100644 index 0000000..980e760 --- /dev/null +++ b/lib/pages/profile/account_delection_page.dart @@ -0,0 +1,105 @@ +import 'package:fcs/domain/entities/setting.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/main/model/main_model.dart'; +import 'package:fcs/pages/widgets/local_app_bar.dart'; +import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:provider/provider.dart'; + +import '../main/model/language_model.dart'; +import '../main/util.dart'; +import '../widgets/local_text.dart'; + +class AccountDelectionPage extends StatefulWidget { + final Function onlogout; + const AccountDelectionPage({Key? key, required this.onlogout}) + : super(key: key); + @override + _AccountDelectionPageState createState() => _AccountDelectionPageState(); +} + +class _AccountDelectionPageState extends State { + bool _isLoading = false; + @override + Widget build(BuildContext context) { + bool isEng = Provider.of(context).isEng; + Setting? setting = Provider.of(context).setting; + String? text = isEng + ? (setting!.deactivateTextEn ?? "") + : (setting!.deactivateTextMm ?? ""); + + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: LocalAppBar( + labelKey: 'profile.delete.title', + backgroundColor: Colors.white, + labelColor: primaryColor, + arrowColor: primaryColor, + ), + body: SafeArea( + child: ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(overscroll: false), + child: ListView( + padding: const EdgeInsets.all(10), + children: [ + Markdown( + shrinkWrap: true, + softLineBreak: true, + physics: const BouncingScrollPhysics(), + data: (text).replaceAll("\\n", '\n'), + styleSheet: MarkdownStyleSheet.fromTheme(ThemeData( + textTheme: TextTheme( + bodyMedium: TextStyle( + fontSize: isEng ? 15 : 14, + color: Colors.black87))))), + const SizedBox( + height: 50, + ), + Container( + padding: const EdgeInsets.all(20), + child: TextButton( + style: TextButton.styleFrom( + foregroundColor: buttonColor, + backgroundColor: primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30.0), + )), + onPressed: () { + showConfirmDialog(context, 'delete.confirm.label', + () { + _deactivate(); + }); + }, + child: LocalText(context, "btn.delete", + fontSize: 15, color: buttonColor))), + ], + ), + ), + ), + ), + ); + } + + _deactivate() async { + try { + setState(() { + _isLoading = true; + }); + + // await context.read().deleteAccount(); + // await widget.onlogout(); + + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } +} diff --git a/lib/pages/profile/profile_page.dart b/lib/pages/profile/profile_page.dart index ee34c96..ce83b58 100644 --- a/lib/pages/profile/profile_page.dart +++ b/lib/pages/profile/profile_page.dart @@ -24,6 +24,8 @@ import 'package:flutter_vector_icons/flutter_vector_icons.dart'; import '../../helpers/theme.dart'; import 'package:collection/collection.dart'; +import 'account_delection_page.dart'; + typedef void ProfileCallback(); class Profile extends StatefulWidget { @@ -82,6 +84,10 @@ class _ProfileState extends State { labelTextKey: "profile.currency", iconData: FontAwesome5Regular.money_bill_alt, ); + final deleteAccountBox = DisplayText( + labelTextKey: "profile.delete.title", + iconData: MaterialCommunityIcons.delete, + ); final phonenumberbox = DisplayText( text: mainModel.user!.phone, @@ -124,8 +130,11 @@ class _ProfileState extends State { ); final logoutbutton = fcsButton( - context, getLocalString(context, "profile.logout"), - callack: _logout, iconData: Icons.exit_to_app); + context, getLocalString(context, "profile.logout"), callack: () { + showConfirmDialog(context, "profile.logout.confirm", () async { + await _logout(); + }); + }, iconData: Icons.exit_to_app); return LocalProgress( inAsyncCall: _isLoading, @@ -181,6 +190,19 @@ class _ProfileState extends State { iconData: Icons.language, isEng: languageModel.isEng, ), + Row( + children: [ + Expanded( + child: deleteAccountBox, + ), + Padding( + padding: const EdgeInsets.only(right: 0), + child: IconButton( + icon: Icon(Icons.edit, color: Colors.grey), + onPressed: _editDelete), + ) + ], + ), getPrivilegeBox(context), SizedBox(height: 15), logoutbutton, @@ -344,6 +366,15 @@ class _ProfileState extends State { ); } + _editDelete() { + Navigator.of(context).push(CupertinoPageRoute( + builder: (context) => AccountDelectionPage( + onlogout: () { + _logout(); + }, + ))); + } + _editName() { Navigator.of(context) .push(CupertinoPageRoute(builder: (context) => ProfileEdit())); @@ -354,25 +385,23 @@ class _ProfileState extends State { CupertinoPageRoute(builder: (context) => ProfileCurrencyEdit())); } - _logout() { - showConfirmDialog(context, "profile.logout.confirm", () async { - setState(() { - _isLoading = true; - }); - try { - await context.read().signout(); - } catch (e) { - } finally { - Future.delayed(Duration(seconds: 1), () { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - }); - Navigator.of(context).pushNamedAndRemoveUntil( - "/welcome", ModalRoute.withName('/welcome')); - } + _logout() async { + setState(() { + _isLoading = true; }); + try { + await context.read().signout(); + } catch (e) { + } finally { + Future.delayed(Duration(seconds: 1), () { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + }); + Navigator.of(context) + .pushNamedAndRemoveUntil("/welcome", ModalRoute.withName('/welcome')); + } } } diff --git a/lib/pages/user_search/user_search.dart b/lib/pages/user_search/user_search.dart index ea88c4e..df94112 100644 --- a/lib/pages/user_search/user_search.dart +++ b/lib/pages/user_search/user_search.dart @@ -79,6 +79,7 @@ class UserSearchDelegate extends SearchDelegate { child: Text( "No result found", textAlign: TextAlign.center, + style: TextStyle(color:Colors.black), ), ), );