From 4e3d2511696f832f553025d144451ee64b13ac05 Mon Sep 17 00:00:00 2001 From: sindhu Date: Mon, 22 Jan 2024 10:25:31 +0700 Subject: [PATCH] step 31 : total history, change password, resize image from camera, update versi 1.2.0 --- app_petty_cash/lib/app/constant.dart | 2 +- app_petty_cash/lib/app/route.dart | 17 + .../lib/model/history_total_model.dart | 17 + .../current_total_history_provider.dart | 9 + .../lib/repository/auth_repository.dart | 28 ++ .../lib/repository/transaksi_repository.dart | 30 ++ .../change_password_provider.dart | 83 ++++ .../change_password_screen.dart | 428 ++++++++++++++++++ .../transaksi/history_total_provider.dart | 79 ++++ .../transaksi/history_transaksi_screen.dart | 103 +++++ .../search_history_transaksi_provider.dart | 19 +- .../screen/transaksi/transaksi_screen.dart | 32 +- app_petty_cash/lib/widget/custom_drawer.dart | 24 +- app_petty_cash/pubspec.lock | 2 +- app_petty_cash/pubspec.yaml | 3 +- 15 files changed, 864 insertions(+), 12 deletions(-) create mode 100644 app_petty_cash/lib/model/history_total_model.dart create mode 100644 app_petty_cash/lib/provider/current_total_history_provider.dart create mode 100644 app_petty_cash/lib/screen/change_password/change_password_provider.dart create mode 100644 app_petty_cash/lib/screen/change_password/change_password_screen.dart create mode 100644 app_petty_cash/lib/screen/transaksi/history_total_provider.dart diff --git a/app_petty_cash/lib/app/constant.dart b/app_petty_cash/lib/app/constant.dart index 8abf404..468db23 100644 --- a/app_petty_cash/lib/app/constant.dart +++ b/app_petty_cash/lib/app/constant.dart @@ -13,7 +13,7 @@ class Constant { // static String version = "1.00"; // NOTE VERSI HARUS SAMA DENGAN PUBSPEC.YAML - static String version = "1.1.5"; + static String version = "1.2.0"; // static String baseUrl = "https://devregonline.pramita.co.id/one-api/xdoc/"; diff --git a/app_petty_cash/lib/app/route.dart b/app_petty_cash/lib/app/route.dart index 41863f5..f4d228e 100644 --- a/app_petty_cash/lib/app/route.dart +++ b/app_petty_cash/lib/app/route.dart @@ -3,6 +3,7 @@ import 'package:app_petty_cash/screen/camera/coba_camera.dart'; import 'package:app_petty_cash/screen/camera/example.dart'; import 'package:flutter/material.dart'; +import '../screen/change_password/change_password_screen.dart'; import '../screen/home/home_screen.dart'; import '../screen/transaksi/history_transaksi_screen.dart'; import '../screen/transaksi/transaksi_screen.dart'; @@ -27,8 +28,24 @@ const cobaCameraRoute = "/cobaCameraRoute"; // test screen const testFilePickerRoute = "/testFilePickerRoute"; +const changePasswordRoute = "/changePasswordRoute"; + class AppRoute { static Route generateRoute(RouteSettings settings) { + + // change password + if (settings.name == changePasswordRoute) { + return MaterialPageRoute(builder: (context) { + return MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaleFactor: 1.0, + padding: EdgeInsets.all(0), + ), + child: ChangePasswordScreen(), + ); + }); + } + // splash screen if (settings.name == splashScreen) { return MaterialPageRoute(builder: (context) { diff --git a/app_petty_cash/lib/model/history_total_model.dart b/app_petty_cash/lib/model/history_total_model.dart new file mode 100644 index 0000000..2d7a709 --- /dev/null +++ b/app_petty_cash/lib/model/history_total_model.dart @@ -0,0 +1,17 @@ +class HistoryTotalModel { + String? totalAll; + + HistoryTotalModel({ + this.totalAll, + }); + + HistoryTotalModel.fromJson(Map json) { + totalAll = json['total_all']; + } + + Map toJson() { + final Map data = new Map(); + data['total_all'] = this.totalAll; + return data; + } +} diff --git a/app_petty_cash/lib/provider/current_total_history_provider.dart b/app_petty_cash/lib/provider/current_total_history_provider.dart new file mode 100644 index 0000000..d23c166 --- /dev/null +++ b/app_petty_cash/lib/provider/current_total_history_provider.dart @@ -0,0 +1,9 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../model/history_total_model.dart'; + +final currentHistoryTotalProvider = StateProvider( + ((ref) => HistoryTotalModel( + totalAll: "0", + )), +); \ No newline at end of file diff --git a/app_petty_cash/lib/repository/auth_repository.dart b/app_petty_cash/lib/repository/auth_repository.dart index 44a7238..413bbab 100644 --- a/app_petty_cash/lib/repository/auth_repository.dart +++ b/app_petty_cash/lib/repository/auth_repository.dart @@ -95,4 +95,32 @@ class AuthRepository extends BaseRepository { return resp['message']; } } + + Future changePassword({ + required String userID, + required String token, + required String tokenx, + required String oldPassword, + required String newPassword, + required String confirmPassword, + }) async { + final param = { + "tokenx": tokenx, + "token": token, + "M_UserID": userID, + "old_password": oldPassword, + "new_password": newPassword, + "confirm_password": confirmPassword + + }; + + final service = "${Constant.baseUrlDevone}auth/change_password"; + final resp = await post(param: param, service: service, token: token); + + if (resp["status"] == "OK") { + return resp['message']; + } else { + return resp['message']; + } + } } diff --git a/app_petty_cash/lib/repository/transaksi_repository.dart b/app_petty_cash/lib/repository/transaksi_repository.dart index 5c90c8f..4bba55b 100644 --- a/app_petty_cash/lib/repository/transaksi_repository.dart +++ b/app_petty_cash/lib/repository/transaksi_repository.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:app_petty_cash/model/list_type_model.dart'; import '../app/constant.dart'; +import '../model/history_total_model.dart'; import '../model/history_transaksi_model.dart'; import '../model/list_category_model.dart'; import 'base_repository.dart'; @@ -216,4 +217,33 @@ class TransaksiRepository extends BaseRepository { return resp['status']; } + + // total by category di history + Future getHistoryTotal( + String companyid, + String tglAwal, + String tglAkhir, + String categoryid, + ) async { + final service = + "${Constant.baseUrlDevone}history/list_total/?companyid=$companyid&startdate=$tglAwal&enddate=$tglAkhir&kategoriid=$categoryid"; + final resp = await get( + // param: { + // "": "", + // }, + service: service, + ); + + print("url total History Transaksi : $service"); + + HistoryTotalModel result = HistoryTotalModel( + totalAll: "0", + ); + + // print(resp['data']); + + final model = HistoryTotalModel.fromJson(resp['data']); + result = model; + return result; + } } diff --git a/app_petty_cash/lib/screen/change_password/change_password_provider.dart b/app_petty_cash/lib/screen/change_password/change_password_provider.dart new file mode 100644 index 0000000..fd55a23 --- /dev/null +++ b/app_petty_cash/lib/screen/change_password/change_password_provider.dart @@ -0,0 +1,83 @@ +import 'package:app_petty_cash/model/auth_model.dart'; +import 'package:app_petty_cash/model/company_model.dart'; +import 'package:app_petty_cash/repository/auth_repository.dart'; +import 'package:app_petty_cash/repository/company_repository.dart'; + +import '../../model/list_category_model.dart'; +import '../../repository/transaksi_repository.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../provider/dio_provider.dart'; +import '../../repository/base_repository.dart'; + +abstract class ChangePasswordState extends Equatable { + final DateTime date; + const ChangePasswordState(this.date); + @override + List get props => [date]; +} + +class ChangePasswordStateInit extends ChangePasswordState { + ChangePasswordStateInit() : super(DateTime.now()); +} + +class ChangePasswordStateLoading extends ChangePasswordState { + ChangePasswordStateLoading() : super(DateTime.now()); +} + +class ChangePasswordStateError extends ChangePasswordState { + final String message; + ChangePasswordStateError({ + required this.message, + }) : super(DateTime.now()); +} + +class ChangePasswordStateDone extends ChangePasswordState { + final String model; + ChangePasswordStateDone({ + required this.model, + }) : super(DateTime.now()); +} + +//notifier +class ChangePasswordNotifier extends StateNotifier { + final Ref ref; + ChangePasswordNotifier({ + required this.ref, + }) : super(ChangePasswordStateInit()); + + void postChangePassword({ + required String userID, + required String userToken, + required String userTokenx, + required String oldPassword, + required String newPassword, + required String confirmPassword, + }) async { + try { + state = ChangePasswordStateLoading(); + final dio = ref.read(dioProvider); + final resp = await AuthRepository(dio: dio).changePassword( + userID: userID, + tokenx: userTokenx, + token: userToken, + oldPassword: oldPassword, + newPassword: newPassword, + confirmPassword: confirmPassword); + state = ChangePasswordStateDone(model: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = ChangePasswordStateError(message: e.message.toString()); + } else { + state = ChangePasswordStateError(message: e.toString()); + } + } + } +} + +//provider +final ChangePasswordProvider = + StateNotifierProvider( + (ref) => ChangePasswordNotifier(ref: ref), +); diff --git a/app_petty_cash/lib/screen/change_password/change_password_screen.dart b/app_petty_cash/lib/screen/change_password/change_password_screen.dart new file mode 100644 index 0000000..9dab139 --- /dev/null +++ b/app_petty_cash/lib/screen/change_password/change_password_screen.dart @@ -0,0 +1,428 @@ +import 'package:app_petty_cash/app/constant.dart'; +import 'package:app_petty_cash/widget/custom_drawer.dart'; +import 'package:app_petty_cash/widget/sankbar_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../app/route.dart'; +import '../../provider/current_user_provider.dart'; +import 'change_password_provider.dart'; + +class ChangePasswordScreen extends HookConsumerWidget { + const ChangePasswordScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedUser = ref.read(currentUserProvider); + //menampung user token jika ada + final userToken = ref.read(currentUserProvider)?.token ?? ""; + final userID = ref.read(currentUserProvider)?.model.M_UserID ?? "0"; + final tokenx = ref.read(currentUserProvider)?.token ?? ""; + + final isLoading = useState(false); + + final obscureTextOldPassword = useState(true); + final obscureTextNewPassword = useState(true); + final obscureTextConfirmPassword = useState(true); + + final ctrlOldPassword = useTextEditingController(text: ""); + final ctrlNewPassword = useTextEditingController(text: ""); + final ctrlConfirmPassword = useTextEditingController(text: ""); + final loading = useState(false); + + // inisialisasi agar bisa cek apakah user sudah login sukses apa belum + useEffect(() { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + final userID = ref.read(currentUserProvider)?.model.M_UserID ?? "0"; + if (userID == "0") { + //not login + Navigator.of(context) + .pushNamedAndRemoveUntil(loginRoute, (route) => true); + + // Navigator.popAndPushNamed(context, loginRoute); + return; + } + }); + return () {}; + }, []); + + // fungsi logout + Logout() async { + final shared = await SharedPreferences.getInstance(); + final bearerString = shared.get(Constant.bearerName).toString(); + // print(bearerString); + if (bearerString.isNotEmpty) { + shared.remove(bearerString); + shared.clear(); + // Navigator.popAndPushNamed(context, loginRoute); + ref.read(currentUserProvider.notifier).state = null; + Navigator.of(context) + .pushNamedAndRemoveUntil(loginRoute, (route) => false); + } + } + + // read provider home + ref.listen( + ChangePasswordProvider, + (previous, next) { + if (next is ChangePasswordStateLoading) { + loading.value = true; + } else if (next is ChangePasswordStateError) { + loading.value = false; + SanckbarWidget(context, next.message, snackbarType.error); + } else if (next is ChangePasswordStateDone) { + loading.value = false; + SanckbarWidget( + context, + "Ubah Password Berhasil!\nSilahkan Login dengan password baru", + snackbarType.success, + ); + Logout(); + } + }, + ); + + return Padding( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 30)), + child: Scaffold( + appBar: AppBar( + // centerTitle: true, + title: Text( + 'Change Password', + style: TextStyle(color: Constant.textWhite), + ), + backgroundColor: Constant.pcBtnBackgroundColor, + iconTheme: IconThemeData( + color: Constant.textWhite, + ), + ), + drawer: CustomDrawer(), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20), + child: Container( + width: Constant.getActualXPhone(context: context, x: 390), + height: Constant.getActualYPhone(context: context, y: 844), + child: Column( + children: [ + //Old password + Padding( + padding: EdgeInsets.only( + // top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: Constant.getActualXPhone(context: context, x: 20), + ), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'Old Password', + style: Constant.body1_400_dibulan(context: context) + .copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ), + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 4), + ), + Padding( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 5), + left: Constant.getActualXPhone(context: context, x: 20), + right: Constant.getActualXPhone(context: context, x: 20), + ), + child: TextField( + obscureText: obscureTextOldPassword.value, + controller: ctrlOldPassword, + decoration: InputDecoration( + suffixIcon: IconButton( + icon: Icon( + obscureTextOldPassword.value + ? Icons.visibility + : Icons.visibility_off, + color: Constant.textGreyv2, + ), + onPressed: () { + obscureTextOldPassword.value = !obscureTextOldPassword.value; + }, + ), + hintStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + labelStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Constant.textGreyv2, + width: 1, + ), + ), + labelText: "OldPassword", + hintText: 'Old Password', + ), + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 40), + ), + //New password + Padding( + padding: EdgeInsets.only( + // top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: Constant.getActualXPhone(context: context, x: 20), + ), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'New Password', + style: Constant.body1_400_dibulan(context: context) + .copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ), + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 4), + ), + Padding( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 5), + left: Constant.getActualXPhone(context: context, x: 20), + right: Constant.getActualXPhone(context: context, x: 20), + ), + child: TextField( + obscureText: obscureTextNewPassword.value, + controller: ctrlNewPassword, + decoration: InputDecoration( + suffixIcon: IconButton( + icon: Icon( + obscureTextNewPassword.value + ? Icons.visibility + : Icons.visibility_off, + color: Constant.textGreyv2, + ), + onPressed: () { + obscureTextNewPassword.value = !obscureTextNewPassword.value; + }, + ), + hintStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + labelStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Constant.textGreyv2, + width: 1, + ), + ), + labelText: "New Password", + hintText: 'New Password', + ), + ), + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 40), + ), + + // Confirm password + Padding( + padding: EdgeInsets.only( + // top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: Constant.getActualXPhone(context: context, x: 20), + ), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'Confirm Password', + style: Constant.body1_400_dibulan(context: context) + .copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ), + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 4), + ), + Padding( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 5), + left: Constant.getActualXPhone(context: context, x: 20), + right: Constant.getActualXPhone(context: context, x: 20), + ), + child: TextField( + obscureText: obscureTextConfirmPassword.value, + controller: ctrlConfirmPassword, + decoration: InputDecoration( + suffixIcon: IconButton( + icon: Icon( + obscureTextConfirmPassword.value + ? Icons.visibility + : Icons.visibility_off, + color: Constant.textGreyv2, + ), + onPressed: () { + obscureTextConfirmPassword.value = !obscureTextConfirmPassword.value; + }, + ), + hintStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + labelStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Constant.textGreyv2, + width: 1, + ), + ), + labelText: "Confirm Password", + hintText: 'Confirm Password', + ), + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 50), + ), + + //Button Update Password + Padding( + padding: EdgeInsets.only( + left: Constant.getActualXPhone(context: context, x: 20), + right: Constant.getActualXPhone(context: context, x: 20), + ), + child: SizedBox( + width: Constant.getActualXPhone(context: context, x: 390), + height: Constant.getActualYPhone(context: context, y: 50), + child: ElevatedButton( + onPressed: (loading.value == true) + ? null + : () { + if (ctrlNewPassword.text != + ctrlConfirmPassword.text) { + SanckbarWidget( + context, + 'New Password dan dan confirm password tidak sama!', + snackbarType.warning); + return; + } + if (ctrlOldPassword.text == + ctrlConfirmPassword.text) { + SanckbarWidget( + context, + 'Password lama dan baru tidak boleh sama', + snackbarType.warning); + return; + } + if (ctrlOldPassword.text.isEmpty || + ctrlNewPassword.text.isEmpty || + ctrlConfirmPassword.text.isEmpty) { + isLoading.value = true; + SanckbarWidget(context, 'Inputan harus diisi', + snackbarType.warning); + } else { + ref + .read(ChangePasswordProvider.notifier) + .postChangePassword( + userTokenx: tokenx, + userToken: userToken, + userID: userID, + oldPassword: ctrlOldPassword.text, + newPassword: ctrlNewPassword.text, + confirmPassword: + ctrlConfirmPassword.text, + ); + } + }, + style: ButtonStyle( + backgroundColor: MaterialStateColor.resolveWith( + (st) => (loading.value == true) + ? Constant.textGrey + : Constant.pcBtnBackgroundColor), + shape: + MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide( + color: Constant.pcBtnBackgroundColor, + ), + ), + ), + shadowColor: + MaterialStateProperty.all(Color(0xffff48423d)), + elevation: MaterialStateProperty.all(4.0), + ), + child: Stack( + children: [ + (isLoading.value) + ? SizedBox( + width: Constant.getActualXPhone( + context: context, x: 24), + height: Constant.getActualYPhone( + context: context, y: 32), + child: Center( + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + ) + : Align( + alignment: Alignment.center, + child: Text( + 'Submit', + style: Constant.titleH3_700( + context: context) + .copyWith( + color: Constant.textLoginColor), + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/app_petty_cash/lib/screen/transaksi/history_total_provider.dart b/app_petty_cash/lib/screen/transaksi/history_total_provider.dart new file mode 100644 index 0000000..73e6aaf --- /dev/null +++ b/app_petty_cash/lib/screen/transaksi/history_total_provider.dart @@ -0,0 +1,79 @@ +import 'package:app_petty_cash/model/history_total_model.dart'; +import 'package:app_petty_cash/provider/current_info_account_balance_provider.dart'; +import 'package:app_petty_cash/repository/home_repository.dart'; +import 'package:app_petty_cash/repository/transaksi_repository.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../model/info_account_balance.dart'; +import '../../provider/dio_provider.dart'; +import '../../repository/base_repository.dart'; + +abstract class HistoryTotalState extends Equatable { + final DateTime date; + const HistoryTotalState(this.date); + @override + List get props => [date]; +} + +class HistoryTotalStateInit extends HistoryTotalState { + HistoryTotalStateInit() : super(DateTime.now()); +} + +class HistoryTotalStateLoading extends HistoryTotalState { + HistoryTotalStateLoading() : super(DateTime.now()); +} + +class HistoryTotalStateError extends HistoryTotalState { + final String message; + HistoryTotalStateError({ + required this.message, + }) : super(DateTime.now()); +} + +class HistoryTotalStateDone extends HistoryTotalState { + final HistoryTotalModel model; + // final String resp; + HistoryTotalStateDone({ + required this.model, + }) : super(DateTime.now()); +} + +//notifier +class HistoryTotalNotifier extends StateNotifier { + final Ref ref; + HistoryTotalNotifier({ + required this.ref, + }) : super(HistoryTotalStateInit()); + + void historyTotal( + String companyid, + String tglAwal, + String tglAkhir, + String categoryid, + ) async { + try { + state = HistoryTotalStateLoading(); + final dio = ref.read(dioProvider); + final resp = await TransaksiRepository(dio: dio).getHistoryTotal( + companyid, + tglAwal, + tglAkhir, + categoryid + ); + state = HistoryTotalStateDone(model: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = HistoryTotalStateError(message: e.message.toString()); + } else { + state = HistoryTotalStateError(message: e.toString()); + } + } + } +} + +//provider +final historyTotalProvider = + StateNotifierProvider( + (ref) => HistoryTotalNotifier(ref: ref), +); diff --git a/app_petty_cash/lib/screen/transaksi/history_transaksi_screen.dart b/app_petty_cash/lib/screen/transaksi/history_transaksi_screen.dart index accb87b..ba19494 100644 --- a/app_petty_cash/lib/screen/transaksi/history_transaksi_screen.dart +++ b/app_petty_cash/lib/screen/transaksi/history_transaksi_screen.dart @@ -1,7 +1,9 @@ import 'dart:convert'; +import 'package:app_petty_cash/model/history_total_model.dart'; import 'package:app_petty_cash/screen/transaksi/confirm_transaksi_provider.dart'; import 'package:app_petty_cash/screen/transaksi/delete_transaksi_provider.dart'; +import 'package:app_petty_cash/screen/transaksi/history_total_provider.dart'; import 'package:app_petty_cash/screen/transaksi/search_history_transaksi_provider.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; @@ -17,6 +19,7 @@ import '../../app/route.dart'; import '../../model/history_transaksi_model.dart'; import '../../model/list_category_model.dart'; import '../../model/list_type_model.dart'; +import '../../provider/current_total_history_provider.dart'; import '../../provider/current_user_provider.dart'; import '../../widget/custom_drawer.dart'; import '../../widget/field_row_history_transaksi.dart'; @@ -64,6 +67,8 @@ class HistoryTransaksiScreen extends HookConsumerWidget { ), ); + final historyTotalLoading = useState(false); + // A. LISTEN PROVIDER // type @@ -142,6 +147,29 @@ class HistoryTransaksiScreen extends HookConsumerWidget { }, ); + // read provider info account balance + ref.listen( + historyTotalProvider, + (previous, next) { + if (next is HistoryTotalStateLoading) { + historyTotalLoading.value = true; + } else if (next is HistoryTotalStateError) { + // print(next.message); + historyTotalLoading.value = false; + SanckbarWidget(context, next.message, snackbarType.error); + } else if (next is HistoryTotalStateDone) { + // print(jsonEncode(next.model)); + // print(next.model.length); + // infoAccountBalanceObject.value = next.model; + ref.read(currentHistoryTotalProvider.notifier).state = + HistoryTotalModel( + totalAll: next.model.totalAll, + ); + historyTotalLoading.value = false; + } + }, + ); + // delete transaksi ref.listen( deleteTransaksiProvider, @@ -1035,6 +1063,81 @@ class HistoryTransaksiScreen extends HookConsumerWidget { // ), // ), + // Total by Filter Category + + if (historyTotalLoading.value) + Center( + child: CircularProgressIndicator(), + ), + + (selectedListCategory.value.categoryid != "ALL" && + historyTotalLoading.value == false) + ? Align( + alignment: Alignment.centerRight, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + 'Kategori Total', + style: + Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack, + ), + ), + SizedBox( + width: Constant.getActualXPhone( + context: context, + x: 4, + ), + ), + Text( + ':', + style: + Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack, + ), + ), + SizedBox( + width: Constant.getActualXPhone( + context: context, + x: 4, + ), + ), + Container( + // width: 100, + width: Constant.getActualXPhone( + context: context, x: 100), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + ref + .read(currentHistoryTotalProvider + .notifier) + .state + .totalAll + .toString(), + style: Constant.body1(context: context) + .copyWith( + fontWeight: FontWeight.w600, + color: Constant.pcBtnBackgroundColor, + ), + ), + ], + ), + ) + ], + ), + ) + : SizedBox.shrink(), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + (searchHistoryIsLoading.value) ? Center( child: CircularProgressIndicator(), diff --git a/app_petty_cash/lib/screen/transaksi/search_history_transaksi_provider.dart b/app_petty_cash/lib/screen/transaksi/search_history_transaksi_provider.dart index d434b69..0f0f8ea 100644 --- a/app_petty_cash/lib/screen/transaksi/search_history_transaksi_provider.dart +++ b/app_petty_cash/lib/screen/transaksi/search_history_transaksi_provider.dart @@ -5,6 +5,7 @@ import '../../model/history_transaksi_model.dart'; import '../../repository/transaksi_repository.dart'; import '../../provider/dio_provider.dart'; import '../../repository/base_repository.dart'; +import 'history_total_provider.dart'; abstract class SearchHistoryTransaksiState extends Equatable { final DateTime date; @@ -47,18 +48,26 @@ class SearchHistoryTransaksiNotifier String companyid, String tglAwal, String tglAkhir, - String categoryid, + String categoryid, ) async { try { state = SearchHistoryTransaksiStateLoading(); final dio = ref.read(dioProvider); final resp = await TransaksiRepository(dio: dio).getListHistoryTransaksi( - companyid, - tglAwal, - tglAkhir, - categoryid, + companyid, + tglAwal, + tglAkhir, + categoryid, ); state = SearchHistoryTransaksiStateDone(model: resp); + + // panggil provider total transaksi by category for non all + ref.read(historyTotalProvider.notifier).historyTotal( + companyid, + tglAwal, + tglAkhir, + categoryid, + ); } catch (e) { if (e is BaseRepositoryException) { state = SearchHistoryTransaksiStateError(message: e.message.toString()); diff --git a/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart b/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart index fca6e7a..58601ea 100644 --- a/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart +++ b/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart @@ -20,10 +20,13 @@ import 'package:intl/intl.dart'; import '../../app/constant.dart'; import '../../model/list_category_model.dart'; +import '../../provider/current_menu_provider.dart'; import '../../provider/current_user_provider.dart'; import '../../widget/custom_drawer.dart'; import '../../widget/sankbar_widget.dart'; +import 'package:image/image.dart' as img; + class DummyDropdownTipe { final String options; final int id; @@ -151,6 +154,8 @@ class TransaksiScreen extends HookConsumerWidget { 'Data Berhasil Disimpan', snackbarType.success, ); + // diupdate ke menu home jika sukses + ref.read(currentPageProvider.notifier).update((state) => 0); Navigator.of(context).pop(); Navigator.of(context).pushNamed(homeRoute); } @@ -194,7 +199,7 @@ class TransaksiScreen extends HookConsumerWidget { final userIDLogin = ref.read(currentUserProvider)?.model.M_UserID ?? "0"; - getBase64() async { + getBase64_v1() async { // List imageBytes = await fileData.value?.readAsBytes(); if (fileData.value != null) { final bytes = io.File(fileData.value!.path).readAsBytesSync(); @@ -211,11 +216,32 @@ class TransaksiScreen extends HookConsumerWidget { } } + getBase64() async { + // List imageBytes = await fileData.value?.readAsBytes(); + if (fileData.value != null) { + final bytes = io.File(fileData.value!.path).readAsBytesSync(); + String base64Image = base64Encode(await fileData.value!.readAsBytes()); + fileDataBase64.value = base64Image; + final file = File(fileData.value!.path); + + print(file.lengthSync() / 1000000); + print(await fileData.value!.length()); + fileSize.value = await fileData.value!.length(); + + // await getExternalStorageDirectory(); + // print(await fileData.value!.saveTo(path)); + print(fileDataBase64.value); + } + } + final ImagePicker _picker = ImagePicker(); pickImage() async { final XFile? pickedFile = await _picker.pickImage( - source: ImageSource.camera, - ); + source: ImageSource.camera, + // maxWidth set untuk width image + maxWidth: 640, + // maxHeight set untuk width image + maxHeight: 480); if (pickedFile != null) { final tmpFile = FilePickerResult([ PlatformFile( diff --git a/app_petty_cash/lib/widget/custom_drawer.dart b/app_petty_cash/lib/widget/custom_drawer.dart index b689133..60c584f 100644 --- a/app_petty_cash/lib/widget/custom_drawer.dart +++ b/app_petty_cash/lib/widget/custom_drawer.dart @@ -251,7 +251,7 @@ class CustomDrawer extends HookConsumerWidget { Navigator.pushNamed(context, reportRoute); }, ), - ListTile( + ListTile( leading: Icon( Icons.account_balance, color: (currentMenu == 4) @@ -273,6 +273,28 @@ class CustomDrawer extends HookConsumerWidget { Navigator.pushNamed(context, changeCompanyRoute); }, ), + ListTile( + leading: Icon( + Icons.lock_reset, + color: (currentMenu == 5) + ? Constant.pcBtnBackgroundColor + : Constant.textGreyv2, + ), + title: Text( + 'Change Password', + style: TextStyle( + color: (currentMenu == 5) + ? Constant.pcBtnBackgroundColor + : Constant.textGreyv2, + ), + ), + onTap: () { + // Handle navigation to Transaksi screen + Navigator.pop(context); + ref.read(currentPageProvider.state).update((state) => 5); + Navigator.pushNamed(context, changePasswordRoute); + }, + ), ListTile( leading: Icon( Icons.logout, diff --git a/app_petty_cash/pubspec.lock b/app_petty_cash/pubspec.lock index 32e6cf8..bb06996 100644 --- a/app_petty_cash/pubspec.lock +++ b/app_petty_cash/pubspec.lock @@ -337,7 +337,7 @@ packages: source: hosted version: "4.0.2" image: - dependency: transitive + dependency: "direct main" description: name: image sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d" diff --git a/app_petty_cash/pubspec.yaml b/app_petty_cash/pubspec.yaml index 8329872..7f9c553 100644 --- a/app_petty_cash/pubspec.yaml +++ b/app_petty_cash/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.1.5 +version: 1.2.0 environment: sdk: '>=3.0.6 <4.0.0' @@ -60,6 +60,7 @@ dependencies: path_provider: ^2.1.2 flutter_share: ^2.0.0 whatsapp_share: ^2.0.2 + image: ^4.1.4 dev_dependencies: flutter_test: