6 Commits

23 changed files with 1153 additions and 192 deletions

View File

@@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application <application
android:label="PettyCash" android:label="PettyCash"
android:name="${applicationName}" android:name="${applicationName}"

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<external-path name="external_storage_directory" path="." /> <external-path name="external_storage_directory" path="." />
<external-path name="external_files" path="."/>
</resources> </resources>

View File

@@ -13,7 +13,7 @@ class Constant {
// static String version = "1.00"; // static String version = "1.00";
// NOTE VERSI HARUS SAMA DENGAN PUBSPEC.YAML // NOTE VERSI HARUS SAMA DENGAN PUBSPEC.YAML
static String version = "1.0.0"; static String version = "1.2.0";
// static String baseUrl = "https://devregonline.pramita.co.id/one-api/xdoc/"; // static String baseUrl = "https://devregonline.pramita.co.id/one-api/xdoc/";

View File

@@ -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:app_petty_cash/screen/camera/example.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../screen/change_password/change_password_screen.dart';
import '../screen/home/home_screen.dart'; import '../screen/home/home_screen.dart';
import '../screen/transaksi/history_transaksi_screen.dart'; import '../screen/transaksi/history_transaksi_screen.dart';
import '../screen/transaksi/transaksi_screen.dart'; import '../screen/transaksi/transaksi_screen.dart';
@@ -27,8 +28,24 @@ const cobaCameraRoute = "/cobaCameraRoute";
// test screen // test screen
const testFilePickerRoute = "/testFilePickerRoute"; const testFilePickerRoute = "/testFilePickerRoute";
const changePasswordRoute = "/changePasswordRoute";
class AppRoute { class AppRoute {
static Route<dynamic> generateRoute(RouteSettings settings) { static Route<dynamic> 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 // splash screen
if (settings.name == splashScreen) { if (settings.name == splashScreen) {
return MaterialPageRoute(builder: (context) { return MaterialPageRoute(builder: (context) {

View File

@@ -0,0 +1,17 @@
class HistoryTotalModel {
String? totalAll;
HistoryTotalModel({
this.totalAll,
});
HistoryTotalModel.fromJson(Map<String, dynamic> json) {
totalAll = json['total_all'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['total_all'] = this.totalAll;
return data;
}
}

View File

@@ -12,6 +12,7 @@ class HistoryTransaksiModel {
String? tanggalconfirm; String? tanggalconfirm;
String? usertransaksi; String? usertransaksi;
String? userconfirm; String? userconfirm;
String? tanggalcreated;
HistoryTransaksiModel( HistoryTransaksiModel(
{this.id, {this.id,
@@ -26,7 +27,9 @@ class HistoryTransaksiModel {
this.isconfirm, this.isconfirm,
this.tanggalconfirm, this.tanggalconfirm,
this.usertransaksi, this.usertransaksi,
this.userconfirm}); this.userconfirm,
this.tanggalcreated
});
HistoryTransaksiModel.fromJson(Map<String, dynamic> json) { HistoryTransaksiModel.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
@@ -42,6 +45,7 @@ class HistoryTransaksiModel {
tanggalconfirm = json['tanggalconfirm']; tanggalconfirm = json['tanggalconfirm'];
usertransaksi = json['usertransaksi']; usertransaksi = json['usertransaksi'];
userconfirm = json['userconfirm']; userconfirm = json['userconfirm'];
tanggalcreated = json['tanggalcreated'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@@ -59,6 +63,7 @@ class HistoryTransaksiModel {
data['tanggalconfirm'] = this.tanggalconfirm; data['tanggalconfirm'] = this.tanggalconfirm;
data['usertransaksi'] = this.usertransaksi; data['usertransaksi'] = this.usertransaksi;
data['userconfirm'] = this.userconfirm; data['userconfirm'] = this.userconfirm;
data['tanggalcreated'] = this.tanggalcreated;
return data; return data;
} }
} }

View File

@@ -12,9 +12,10 @@ class ListTransaksiHomeModel {
String? tanggalconfirm; String? tanggalconfirm;
String? usertransaksi; String? usertransaksi;
String? userconfirm; String? userconfirm;
String? tanggalcreated;
ListTransaksiHomeModel( ListTransaksiHomeModel({
{this.id, this.id,
this.tanggaltransaksi, this.tanggaltransaksi,
this.tipe, this.tipe,
this.kategoriid, this.kategoriid,
@@ -26,7 +27,9 @@ class ListTransaksiHomeModel {
this.isconfirm, this.isconfirm,
this.tanggalconfirm, this.tanggalconfirm,
this.usertransaksi, this.usertransaksi,
this.userconfirm}); this.userconfirm,
this.tanggalcreated,
});
ListTransaksiHomeModel.fromJson(Map<String, dynamic> json) { ListTransaksiHomeModel.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
@@ -42,6 +45,7 @@ class ListTransaksiHomeModel {
tanggalconfirm = json['tanggalconfirm']; tanggalconfirm = json['tanggalconfirm'];
usertransaksi = json['usertransaksi']; usertransaksi = json['usertransaksi'];
userconfirm = json['userconfirm']; userconfirm = json['userconfirm'];
tanggalcreated = json['tanggalcreated'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@@ -59,6 +63,7 @@ class ListTransaksiHomeModel {
data['tanggalconfirm'] = this.tanggalconfirm; data['tanggalconfirm'] = this.tanggalconfirm;
data['usertransaksi'] = this.usertransaksi; data['usertransaksi'] = this.usertransaksi;
data['userconfirm'] = this.userconfirm; data['userconfirm'] = this.userconfirm;
data['tanggalcreated'] = this.tanggalcreated;
return data; return data;
} }
} }

View File

@@ -0,0 +1,9 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../model/history_total_model.dart';
final currentHistoryTotalProvider = StateProvider<HistoryTotalModel>(
((ref) => HistoryTotalModel(
totalAll: "0",
)),
);

View File

@@ -95,4 +95,32 @@ class AuthRepository extends BaseRepository {
return resp['message']; return resp['message'];
} }
} }
Future<String> 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'];
}
}
} }

View File

@@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:app_petty_cash/model/list_type_model.dart'; import 'package:app_petty_cash/model/list_type_model.dart';
import '../app/constant.dart'; import '../app/constant.dart';
import '../model/history_total_model.dart';
import '../model/history_transaksi_model.dart'; import '../model/history_transaksi_model.dart';
import '../model/list_category_model.dart'; import '../model/list_category_model.dart';
import 'base_repository.dart'; import 'base_repository.dart';
@@ -100,6 +101,7 @@ class TransaksiRepository extends BaseRepository {
'userid': userid, 'userid': userid,
'sender': sender, 'sender': sender,
'companyid': M_CompanyID, 'companyid': M_CompanyID,
'base64File': base64file,
'fileName': fileName, 'fileName': fileName,
'fileSize': fileSize, 'fileSize': fileSize,
'fileEkstension': fileExtension 'fileEkstension': fileExtension
@@ -139,7 +141,7 @@ class TransaksiRepository extends BaseRepository {
String categoryid, String categoryid,
) async { ) async {
final service = final service =
"${Constant.baseUrlDevone}/homescreen/list_transaction/?companyid=$companyid&startdate=$tglAwal&enddate=$tglAkhir&kategoriid=$categoryid"; "${Constant.baseUrlDevone}/history/list_transaction/?companyid=$companyid&startdate=$tglAwal&enddate=$tglAkhir&kategoriid=$categoryid";
// https://devone.aplikasi.web.id/one-api-pettycash/pettycash/history/list_transaction/?companyid=1&startdate=2023-12-01&enddate=2023-12-30&kategoriid=0 // https://devone.aplikasi.web.id/one-api-pettycash/pettycash/history/list_transaction/?companyid=1&startdate=2023-12-01&enddate=2023-12-30&kategoriid=0
final resp = await get( final resp = await get(
// param: { // param: {
@@ -215,4 +217,33 @@ class TransaksiRepository extends BaseRepository {
return resp['status']; return resp['status'];
} }
// total by category di history
Future<HistoryTotalModel> 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;
}
} }

View File

@@ -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<Object?> 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<ChangePasswordState> {
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<ChangePasswordNotifier, ChangePasswordState>(
(ref) => ChangePasswordNotifier(ref: ref),
);

View File

@@ -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<bool>(true);
final obscureTextNewPassword = useState<bool>(true);
final obscureTextConfirmPassword = useState<bool>(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>(
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),
),
),
],
),
),
),
),
],
),
),
),
),
),
);
}
}

View File

@@ -5,6 +5,7 @@ import 'package:app_petty_cash/screen/home/list_transaksi_home_provider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../../app/constant.dart'; import '../../app/constant.dart';
@@ -140,6 +141,25 @@ class HomeScreen extends HookConsumerWidget {
}, },
); );
String formatDateString(String inputDate) {
try {
// Parsing tanggal dari string input
DateTime date =
DateFormat('dd-MM-yyyy HH:mm:ss', 'id').parse(inputDate);
// Format tanggal ke '30 Des 2023'
String formattedDate =
DateFormat('dd MMM yyyy HH:mm:ss', 'id').format(date);
return formattedDate;
} catch (e) {
// Tangkap kesalahan jika format tanggal tidak sesuai
print('Error parsing date: $e');
// return 'Format Tanggal Salah';
return inputDate;
}
}
return Padding( return Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: Constant.getActualYPhone(context: context, y: 30), top: Constant.getActualYPhone(context: context, y: 30),
@@ -400,6 +420,85 @@ class HomeScreen extends HookConsumerWidget {
.value[idx].tipe .value[idx].tipe
.toString(), .toString(),
), ),
SizedBox(
height: Constant.getActualYPhone(
context: context, y: 10),
),
// catatan
Align(
alignment: Alignment.centerLeft,
child: Text(
listTransaksiHome
.value[idx].note
.toString(),
style: Constant.body1(
context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.textBlack,
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context, y: 10),
),
// Tanggal Created and by align right
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Text(
'created : ' +
formatDateString(
listTransaksiHome
.value[idx]
.tanggalcreated
.toString(),
),
overflow:
TextOverflow.ellipsis,
style: Constant.body1(
context: context)
.copyWith(
fontWeight:
FontWeight.normal,
fontStyle: FontStyle.italic,
color: Constant.textBlack,
fontSize: 14,
),
),
Expanded(
child: Container(
child: Text(
' by : ' +
listTransaksiHome
.value[idx]
.usertransaksi
.toString(),
overflow:
TextOverflow.ellipsis,
style: Constant.body1(
context: context)
.copyWith(
fontWeight:
FontWeight.normal,
fontStyle:
FontStyle.italic,
color: Constant
.pcBtnBackgroundColor,
fontSize: 14,
),
),
),
),
],
),
], ],
), ),
), ),

View File

@@ -31,6 +31,10 @@ class ReportScreen extends HookConsumerWidget {
final tglAkhirTmp = useState<String>(""); final tglAkhirTmp = useState<String>("");
String M_CompanyID = "0"; String M_CompanyID = "0";
String timeStamp = DateFormat('dd-MM-yyyy').format(
DateTime.now(),
);
Future<String> getCompanyID() async { Future<String> getCompanyID() async {
final shared = await SharedPreferences.getInstance(); final shared = await SharedPreferences.getInstance();
String M_CompanyID = "0"; String M_CompanyID = "0";
@@ -329,7 +333,8 @@ class ReportScreen extends HookConsumerWidget {
onPressed: () async { onPressed: () async {
M_CompanyID = await getCompanyID(); M_CompanyID = await getCompanyID();
if (M_CompanyID == "0") { if (M_CompanyID == "0") {
SanckbarWidget(context, 'Invalid Company', snackbarType.error); SanckbarWidget(
context, 'Invalid Company', snackbarType.error);
return; return;
} }
// Awal // Awal
@@ -343,13 +348,13 @@ class ReportScreen extends HookConsumerWidget {
// Akhir // Akhir
DateTime parsedDateAkhir = DateTime parsedDateAkhir =
DateFormat('dd-MM-yyyy').parse( DateFormat('dd-MM-yyyy').parse(
ctrlTglAwal.value.text.toString(), ctrlTglAkhir.value.text.toString(),
); );
String formattedDateAkhir = String formattedDateAkhir =
DateFormat('yyyy-MM-dd').format(parsedDateAkhir); DateFormat('yyyy-MM-dd').format(parsedDateAkhir);
String url = String url =
"https://${Constant.baseUrlDevoneReport}/birt/run?__report=report/one/pettycash/rpt_r_pt_001.rptdesign&__format=xls&PStartDate=$formattedDateAwal&PEndDate=$formattedDateAkhir&PCompanyID=$M_CompanyID&username=adminsas%20"; "https://${Constant.baseUrlDevoneReport}/birt/run?__report=report/one/pettycash/rpt_r_pt_001.rptdesign&__format=xls&PStartDate=$formattedDateAwal&PEndDate=$formattedDateAkhir&PCompanyID=$M_CompanyID&username=adminsas%20&tm=$timeStamp";
if (!await launchUrl(Uri.parse(url))) { if (!await launchUrl(Uri.parse(url))) {
// throw Exception('Could not launch $url'); // throw Exception('Could not launch $url');
SanckbarWidget(context, 'Could not launch $url', SanckbarWidget(context, 'Could not launch $url',
@@ -407,7 +412,8 @@ class ReportScreen extends HookConsumerWidget {
onPressed: () async { onPressed: () async {
M_CompanyID = await getCompanyID(); M_CompanyID = await getCompanyID();
if (M_CompanyID == "0") { if (M_CompanyID == "0") {
SanckbarWidget(context, 'Invalid Company', snackbarType.error); SanckbarWidget(
context, 'Invalid Company', snackbarType.error);
return; return;
} }
// Awal // Awal
@@ -421,13 +427,15 @@ class ReportScreen extends HookConsumerWidget {
// Akhir // Akhir
DateTime parsedDateAkhir = DateTime parsedDateAkhir =
DateFormat('dd-MM-yyyy').parse( DateFormat('dd-MM-yyyy').parse(
ctrlTglAwal.value.text.toString(), ctrlTglAkhir.value.text.toString(),
); );
String formattedDateAkhir = String formattedDateAkhir =
DateFormat('yyyy-MM-dd').format(parsedDateAkhir); DateFormat('yyyy-MM-dd').format(parsedDateAkhir);
String url = String url =
"https://${Constant.baseUrlDevoneReport}/birt/run?__report=report/one/pettycash/rpt_r_pt_001.rptdesign&__format=pdf&PStartDate=$formattedDateAwal&PEndDate=$formattedDateAkhir&PCompanyID=$M_CompanyID&username=adminsas%20"; "https://${Constant.baseUrlDevoneReport}/birt/run?__report=report/one/pettycash/rpt_r_pt_001.rptdesign&__format=pdf&PStartDate=$formattedDateAwal&PEndDate=$formattedDateAkhir&PCompanyID=$M_CompanyID&username=adminsas%20&tm=$timeStamp";
print(url);
if (!await launchUrl(Uri.parse(url))) { if (!await launchUrl(Uri.parse(url))) {
// throw Exception('Could not launch $url'); // throw Exception('Could not launch $url');
SanckbarWidget(context, 'Could not launch $url', SanckbarWidget(context, 'Could not launch $url',

View File

@@ -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<Object?> 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<HistoryTotalState> {
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<HistoryTotalNotifier, HistoryTotalState>(
(ref) => HistoryTotalNotifier(ref: ref),
);

View File

@@ -1,7 +1,9 @@
import 'dart:convert'; 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/confirm_transaksi_provider.dart';
import 'package:app_petty_cash/screen/transaksi/delete_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:app_petty_cash/screen/transaksi/search_history_transaksi_provider.dart';
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -17,6 +19,7 @@ import '../../app/route.dart';
import '../../model/history_transaksi_model.dart'; import '../../model/history_transaksi_model.dart';
import '../../model/list_category_model.dart'; import '../../model/list_category_model.dart';
import '../../model/list_type_model.dart'; import '../../model/list_type_model.dart';
import '../../provider/current_total_history_provider.dart';
import '../../provider/current_user_provider.dart'; import '../../provider/current_user_provider.dart';
import '../../widget/custom_drawer.dart'; import '../../widget/custom_drawer.dart';
import '../../widget/field_row_history_transaksi.dart'; import '../../widget/field_row_history_transaksi.dart';
@@ -64,6 +67,8 @@ class HistoryTransaksiScreen extends HookConsumerWidget {
), ),
); );
final historyTotalLoading = useState(false);
// A. LISTEN PROVIDER // A. LISTEN PROVIDER
// type // 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 // delete transaksi
ref.listen( ref.listen(
deleteTransaksiProvider, deleteTransaksiProvider,
@@ -464,6 +492,25 @@ class HistoryTransaksiScreen extends HookConsumerWidget {
final FocusNode focusNodetglAkhir = useFocusNode(); final FocusNode focusNodetglAkhir = useFocusNode();
final tglAkhirHasFocus = useState(false); final tglAkhirHasFocus = useState(false);
String formatDateString(String inputDate) {
try {
// Parsing tanggal dari string input
DateTime date =
DateFormat('dd-MM-yyyy HH:mm:ss', 'id').parse(inputDate);
// Format tanggal ke '30 Des 2023'
String formattedDate =
DateFormat('dd MMM yyyy HH:mm:ss', 'id').format(date);
return formattedDate;
} catch (e) {
// Tangkap kesalahan jika format tanggal tidak sesuai
print('Error parsing date: $e');
// return 'Format Tanggal Salah';
return inputDate;
}
}
return GestureDetector( return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(), onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Padding( child: Padding(
@@ -736,6 +783,7 @@ class HistoryTransaksiScreen extends HookConsumerWidget {
value: option, value: option,
child: Text( child: Text(
option.categoryname ?? "", option.categoryname ?? "",
overflow: TextOverflow.ellipsis,
style: Constant.body1(context: context) style: Constant.body1(context: context)
.copyWith( .copyWith(
color: Constant.textBlack, color: Constant.textBlack,
@@ -875,13 +923,27 @@ class HistoryTransaksiScreen extends HookConsumerWidget {
], ],
), ),
onPressed: () async { onPressed: () async {
DateTime parsedDate =
DateFormat('dd-MM-yyyy').parse(
ctrlTglAwal.value.text.toString(),
);
String formattedDateAwal =
DateFormat('yyyy-MM-dd').format(parsedDate);
DateTime parsedDateAkhir =
DateFormat('dd-MM-yyyy').parse(
ctrlTglAkhir.value.text.toString(),
);
String formattedDateAkhir = DateFormat('yyyy-MM-dd')
.format(parsedDateAkhir);
M_CompanyID.value = await getCompanyID(); M_CompanyID.value = await getCompanyID();
ref ref
.read(searchHistoryTransaksiProvider.notifier) .read(searchHistoryTransaksiProvider.notifier)
.searchHistoryTransaksi( .searchHistoryTransaksi(
M_CompanyID.value, M_CompanyID.value,
ctrlTglAwal.text, formattedDateAwal,
ctrlTglAkhir.text, formattedDateAkhir,
selectedListCategory.value.categoryid ?? "0", selectedListCategory.value.categoryid ?? "0",
); );
}, },
@@ -1001,6 +1063,70 @@ 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,
),
),
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) (searchHistoryIsLoading.value)
? Center( ? Center(
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
@@ -1080,7 +1206,27 @@ class HistoryTransaksiScreen extends HookConsumerWidget {
// ), // ),
SizedBox( SizedBox(
height: Constant.getActualYPhone( height: Constant.getActualYPhone(
context: context, y: 6), context: context, y: 10),
),
// catatan
Align(
alignment: Alignment.centerLeft,
child: Text(
listSearchHistory.value[idx].note
.toString(),
style: Constant.body1(
context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.textBlack,
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context, y: 10),
), ),
if (listSearchHistory if (listSearchHistory
@@ -1308,70 +1454,70 @@ class HistoryTransaksiScreen extends HookConsumerWidget {
), ),
], ],
), ),
// Row( // Tanggal Created dan by align right
// children: [
// Container( Column(
// width: Constant.getActualXPhone( children: [
// context: context, x: 40), Align(
// height: Constant.getActualYPhone( alignment:
// context: context, Alignment.centerRight,
// y: 40, child: Row(
// ), mainAxisAlignment:
// child: Image.asset( MainAxisAlignment.end,
// "images/icon_delete.png", children: [
// // scale: 1, Text(
// ), 'created : ' +
// ), formatDateString(
// SizedBox( listSearchHistory
// height: Constant.getActualYPhone( .value[idx]
// context: context, y: 12), .tanggalcreated
// ), .toString(),
// Expanded( ),
// child: ElevatedButton( overflow:
// style: ButtonStyle( TextOverflow.ellipsis,
// backgroundColor: MaterialStateColor style: Constant.body1(
// .resolveWith((st) => Constant context: context)
// .pcBtnBackgroundColor), .copyWith(
// shape: fontWeight:
// MaterialStateProperty.all< FontWeight.normal,
// RoundedRectangleBorder>( fontStyle:
// RoundedRectangleBorder( FontStyle.italic,
// borderRadius: color:
// BorderRadius.circular( Constant.textBlack,
// 8), fontSize: 14,
// side: BorderSide( ),
// color: Constant ),
// .pcBtnBackgroundColor, Expanded(
// ), child: Container(
// ), child: Text(
// ), ' by : ' +
// shadowColor: listSearchHistory
// MaterialStateProperty.all( .value[idx]
// Color(0xffff48423d)), .usertransaksi
// elevation: .toString(),
// MaterialStateProperty.all( overflow: TextOverflow
// 4.0), .ellipsis,
// ), style: Constant.body1(
// child: Stack( context:
// children: [ context)
// Text( .copyWith(
// 'Confirmed', fontWeight:
// style: Constant.body1( FontWeight
// context: context) .normal,
// .copyWith( fontStyle: FontStyle
// fontWeight: .italic,
// FontWeight color: Constant
// .w600, .pcBtnBackgroundColor,
// color: Constant fontSize: 14,
// .white), ),
// ), ),
// ], ),
// ), ),
// onPressed: () {}, ],
// ), ),
// ), ),
// ], ],
// ), ),
], ],
), ),
), ),

View File

@@ -5,6 +5,7 @@ import '../../model/history_transaksi_model.dart';
import '../../repository/transaksi_repository.dart'; import '../../repository/transaksi_repository.dart';
import '../../provider/dio_provider.dart'; import '../../provider/dio_provider.dart';
import '../../repository/base_repository.dart'; import '../../repository/base_repository.dart';
import 'history_total_provider.dart';
abstract class SearchHistoryTransaksiState extends Equatable { abstract class SearchHistoryTransaksiState extends Equatable {
final DateTime date; final DateTime date;
@@ -59,6 +60,14 @@ class SearchHistoryTransaksiNotifier
categoryid, categoryid,
); );
state = SearchHistoryTransaksiStateDone(model: resp); state = SearchHistoryTransaksiStateDone(model: resp);
// panggil provider total transaksi by category for non all
ref.read(historyTotalProvider.notifier).historyTotal(
companyid,
tglAwal,
tglAkhir,
categoryid,
);
} catch (e) { } catch (e) {
if (e is BaseRepositoryException) { if (e is BaseRepositoryException) {
state = SearchHistoryTransaksiStateError(message: e.message.toString()); state = SearchHistoryTransaksiStateError(message: e.message.toString());

View File

@@ -20,10 +20,13 @@ import 'package:intl/intl.dart';
import '../../app/constant.dart'; import '../../app/constant.dart';
import '../../model/list_category_model.dart'; import '../../model/list_category_model.dart';
import '../../provider/current_menu_provider.dart';
import '../../provider/current_user_provider.dart'; import '../../provider/current_user_provider.dart';
import '../../widget/custom_drawer.dart'; import '../../widget/custom_drawer.dart';
import '../../widget/sankbar_widget.dart'; import '../../widget/sankbar_widget.dart';
import 'package:image/image.dart' as img;
class DummyDropdownTipe { class DummyDropdownTipe {
final String options; final String options;
final int id; final int id;
@@ -151,6 +154,8 @@ class TransaksiScreen extends HookConsumerWidget {
'Data Berhasil Disimpan', 'Data Berhasil Disimpan',
snackbarType.success, snackbarType.success,
); );
// diupdate ke menu home jika sukses
ref.read(currentPageProvider.notifier).update((state) => 0);
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pushNamed(homeRoute); Navigator.of(context).pushNamed(homeRoute);
} }
@@ -194,7 +199,7 @@ class TransaksiScreen extends HookConsumerWidget {
final userIDLogin = ref.read(currentUserProvider)?.model.M_UserID ?? "0"; final userIDLogin = ref.read(currentUserProvider)?.model.M_UserID ?? "0";
getBase64() async { getBase64_v1() async {
// List<int> imageBytes = await fileData.value?.readAsBytes(); // List<int> imageBytes = await fileData.value?.readAsBytes();
if (fileData.value != null) { if (fileData.value != null) {
final bytes = io.File(fileData.value!.path).readAsBytesSync(); final bytes = io.File(fileData.value!.path).readAsBytesSync();
@@ -211,11 +216,32 @@ class TransaksiScreen extends HookConsumerWidget {
} }
} }
getBase64() async {
// List<int> 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(); final ImagePicker _picker = ImagePicker();
pickImage() async { pickImage() async {
final XFile? pickedFile = await _picker.pickImage( 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) { if (pickedFile != null) {
final tmpFile = FilePickerResult([ final tmpFile = FilePickerResult([
PlatformFile( PlatformFile(

View File

@@ -39,6 +39,7 @@ class TransaksiSelectKategoriWidget extends StatelessWidget {
value: option, value: option,
child: Text( child: Text(
option.categoryname ?? "", option.categoryname ?? "",
overflow: TextOverflow.ellipsis,
style: Constant.body1(context: context).copyWith( style: Constant.body1(context: context).copyWith(
color: Constant.textBlack, fontWeight: FontWeight.w400), color: Constant.textBlack, fontWeight: FontWeight.w400),
), ),

View File

@@ -273,6 +273,28 @@ class CustomDrawer extends HookConsumerWidget {
Navigator.pushNamed(context, changeCompanyRoute); 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( ListTile(
leading: Icon( leading: Icon(
Icons.logout, Icons.logout,

View File

@@ -211,71 +211,6 @@ class HistoryRowAtasWidget extends HookConsumerWidget {
Radius.circular(8.0), Radius.circular(8.0),
), ),
), ),
// child: Text('s'),
// child: FutureBuilder<Widget>(
// future: checkFileExistence(
// 'https://devone.aplikasi.web.id/pettycash-media/icon/icon_$icon_category_id.svg',
// ),
// builder: (context, snapshot) {
// // if (snapshot.connectionState == ConnectionState.waiting) {
// // // return CircularProgressIndicator();
// // return Text('');
// // } else if (snapshot.hasError) {
// // return Icon(
// // Icons.error,
// // color: Colors.red,
// // );
// // } else {
// // return snapshot.data ?? Container();
// // }
// if (snapshot.connectionState == ConnectionState.done) {
// return snapshot.data ?? Container();
// } else if (snapshot.hasError) {
// return Icon(
// Icons.error,
// color: Colors.red,
// );
// } else {
// return Text('');
// }
// },
// ),
// child: Consumer(
// builder: (context, watch, child) {
// String iconUrl =
// 'https://devone.aplikasi.web.id/pettycash-media/icon/icon_$icon_category_id.svg';
// final iconAsyncValue = ref.read(
// iconProvider(
// iconUrl,
// ),
// );
// return iconAsyncValue.when(
// loading: () {
// print('loading iconurl : $iconUrl');
// return CircularProgressIndicator();
// },
// error: (error, stackTrace) {
// print('error iconurl : $iconUrl');
// return Icon(
// Icons.error,
// color: Colors.red,
// );
// },
// data: (iconWidget) {
// print('data iconurl : $iconUrl');
// return iconWidget ?? Container();
// }
// );
// },
// ),
// child: SvgPicture.network(
// 'https://devone.aplikasi.web.id/pettycash-media/icon/icon_$icon_category_id.svg',
// semanticsLabel: 'Icon pizza',
// ),
child: getIconUrl(icon_category_id), child: getIconUrl(icon_category_id),
), ),

View File

@@ -85,10 +85,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.18.0" version: "1.17.1"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@@ -278,6 +278,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
flutter_share:
dependency: "direct main"
description:
name: flutter_share
sha256: ae12c1cea13b35926a109824ffac601531e40cb94ad53eeae58625eceb3eaaaa
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_svg: flutter_svg:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -329,7 +337,7 @@ packages:
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
image: image:
dependency: transitive dependency: "direct main"
description: description:
name: image name: image
sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d" sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d"
@@ -436,26 +444,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.16" version: "0.12.15"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0" version: "0.2.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.9.1"
mime: mime:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -689,18 +697,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.9.1"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.1" version: "1.11.0"
state_notifier: state_notifier:
dependency: transitive dependency: transitive
description: description:
@@ -713,10 +721,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.1"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
@@ -737,10 +745,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.5.1"
top_snackbar_flutter: top_snackbar_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -893,14 +901,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.17" version: "2.0.17"
web: whatsapp_share:
dependency: transitive dependency: "direct main"
description: description:
name: web name: whatsapp_share
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 sha256: d1884f302a52d9f400bc3d7d4274b77aad83424e08f425351cea8d13b4cb8649
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.0" version: "2.0.2"
win32: win32:
dependency: transitive dependency: transitive
description: description:
@@ -934,5 +942,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.2.0-194.0.dev <4.0.0" dart: ">=3.0.6 <4.0.0"
flutter: ">=3.10.0" flutter: ">=3.10.0"

View File

@@ -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 # 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 # 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. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1 version: 1.2.0
environment: environment:
sdk: '>=3.0.6 <4.0.0' sdk: '>=3.0.6 <4.0.0'
@@ -58,6 +58,9 @@ dependencies:
photo_view: ^0.14.0 photo_view: ^0.14.0
mime: ^1.0.4 mime: ^1.0.4
path_provider: ^2.1.2 path_provider: ^2.1.2
flutter_share: ^2.0.0
whatsapp_share: ^2.0.2
image: ^4.1.4
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: