upload file & revisi ui

This commit is contained in:
Sas Andy
2024-01-17 13:27:45 +07:00
parent 578e296097
commit 431c4f0039
7 changed files with 292 additions and 188 deletions

View File

@@ -19,6 +19,9 @@ class Constant {
static String baseUrlDevone =
"https://devone.aplikasi.web.id/one-api-pettycash/pettycash/";
// "http://devone.aplikasi.web.id/one-api-pettycash/pettycash/";
static String baseUrlFile =
"https://devone.aplikasi.web.id/pettycash-media/attachment/";
// static String baseUrl_appdoctor =
// "http://devbandungraya.aplikasi.web.id/one-api/app_doctor/";

View File

@@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:app_petty_cash/model/list_type_model.dart';
import '../app/constant.dart';
@@ -57,34 +59,68 @@ class TransaksiRepository extends BaseRepository {
String catatan,
String userid,
String sender,
String base64file,
String fileName,
String fileSize,
String fileExtension,
String url) async {
String paramPostInUrl = "";
// String paramPostInUrl = "";
Map<String, dynamic> prm = {};
String M_CompanyID = await getCompanyID();
if (tipe == "DEBIT") {
sender = "";
paramPostInUrl =
"?tanggal=$tanggal&tipe=$tipe&kategoriid=$kategoriid&jumlah=$jumlah&catatan=$catatan&url=$url&userid=$userid&sender=$sender";
prm = {
'tanggal': tanggal,
'tipe': tipe,
'kategoriid': kategoriid,
'jumlah': jumlah,
'catatan': catatan,
'url': url,
'userid': userid,
'sender': sender,
'companyid': M_CompanyID,
'base64File': base64file,
'fileName': fileName,
'fileSize': fileSize,
'fileEkstension': fileExtension
};
// paramPostInUrl =
// "?tanggal=$tanggal&tipe=$tipe&kategoriid=$kategoriid&jumlah=$jumlah&catatan=$catatan&url=$url&userid=$userid&sender=$sender";
} else {
if (tipe == "KREDIT") {
kategoriid = "0";
paramPostInUrl =
"?tanggal=$tanggal&tipe=$tipe&kategoriid=$kategoriid&jumlah=$jumlah&catatan=$catatan&url=$url&userid=$userid&sender=$sender";
prm = {
'tanggal': tanggal,
'tipe': tipe,
'kategoriid': kategoriid,
'jumlah': jumlah,
'catatan': catatan,
'url': url,
'userid': userid,
'sender': sender,
'companyid': M_CompanyID,
'fileName': fileName,
'fileSize': fileSize,
'fileEkstension': fileExtension
};
// paramPostInUrl =
// "?tanggal=$tanggal&tipe=$tipe&kategoriid=$kategoriid&jumlah=$jumlah&catatan=$catatan&url=$url&userid=$userid&sender=$sender";
}
}
paramPostInUrl += "&companyid=$M_CompanyID";
// paramPostInUrl += "&companyid=$M_CompanyID";
// /?tanggal=2023-12-29&tipe=KREDIT&kategoriid=3&jumlah=5000&catatan=Lakban%20Besar&url=&userid=1&sender=
final service =
"${Constant.baseUrlDevone}transaction/addtransaction/$paramPostInUrl";
final resp = await get(
// param: {
// "": "",
// },
service: service,
);
final service = "${Constant.baseUrlDevone}transaction/addtransaction";
final resp = await post(
// param: {
// "": "",
// },
service: service,
param: prm);
print("url insert transaksi : $service");
print("prm insert transaksi : ${jsonEncode(prm)}");
// final result = List<ListCategory>.empty(growable: true);
// resp['data'].forEach((e) {
@@ -127,7 +163,6 @@ class TransaksiRepository extends BaseRepository {
String id,
String userid,
) async {
final service =
"${Constant.baseUrlDevone}transaction/deletetransaction/?id=$id&userid=$userid";
final resp = await get(
@@ -145,7 +180,7 @@ class TransaksiRepository extends BaseRepository {
// result.add(model);
// });
if(resp['status'] != "OK"){
if (resp['status'] != "OK") {
return resp['message'];
}

View File

@@ -43,15 +43,18 @@ class InsertTransaksiNotifier extends StateNotifier<InsertTransaksiState> {
}) : super(InsertTransaksiStateInit());
void insertTransaksi(
String tanggal,
String tipe,
String kategoriid,
String jumlah,
String catatan,
String userid,
String sender,
String url,
) async {
{required String tanggal,
required String tipe,
required String kategoriid,
required String jumlah,
required String catatan,
required String userid,
required String sender,
required String url,
required String base64file,
required String fileName,
required String fileSize,
required String fileExtension}) async {
try {
state = InsertTransaksiStateLoading();
final dio = ref.read(dioProvider);
@@ -63,6 +66,10 @@ class InsertTransaksiNotifier extends StateNotifier<InsertTransaksiState> {
catatan,
userid,
sender,
base64file,
fileName,
fileSize,
fileExtension,
url,
);
state = InsertTransaksiStateDone(resp: resp);

View File

@@ -3,16 +3,17 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class TransaksiPickDateWidget extends StatelessWidget {
const TransaksiPickDateWidget({
super.key,
required this.ctrlTglAwal,
required this.tglAwal,
required this.tglAwalTmp,
});
const TransaksiPickDateWidget(
{super.key,
required this.ctrlTglAwal,
required this.tglAwal,
required this.tglAwalTmp,
required this.isLoading});
final TextEditingController ctrlTglAwal;
final ValueNotifier<DateTime> tglAwal;
final ValueNotifier<String> tglAwalTmp;
final ValueNotifier<bool> isLoading;
@override
Widget build(BuildContext context) {
@@ -63,35 +64,38 @@ class TransaksiPickDateWidget extends StatelessWidget {
// color: Constant.colorIconDate,
// ),
),
onTap: () async {
final selectedDateAwal = await showDatePicker(
keyboardType: TextInputType.none,
// locale: const Locale("en-CA"),
// locale: ,
context: context,
initialEntryMode: DatePickerEntryMode.calendarOnly,
firstDate: DateTime(2000),
lastDate: DateTime(2100),
onTap: !isLoading.value
? () async {
final selectedDateAwal = await showDatePicker(
keyboardType: TextInputType.none,
// locale: const Locale("en-CA"),
// locale: ,
context: context,
initialEntryMode: DatePickerEntryMode.calendarOnly,
firstDate: DateTime(2000),
lastDate: DateTime(2100),
initialDate:
(ctrlTglAwal.text.isEmpty) ? DateTime.now() : tglAwal.value,
);
initialDate: (ctrlTglAwal.text.isEmpty)
? DateTime.now()
: tglAwal.value,
);
if (selectedDateAwal != null) {
String formattedDate =
DateFormat('dd-MM-yyyy').format(selectedDateAwal);
// ctrlTglAwal.text =
// selectedDateAwal.toString().split(' ')[0];
ctrlTglAwal.text = formattedDate;
tglAwal.value = selectedDateAwal;
tglAwalTmp.value = selectedDateAwal.toString();
}
if (selectedDateAwal != null) {
String formattedDate =
DateFormat('dd-MM-yyyy').format(selectedDateAwal);
// ctrlTglAwal.text =
// selectedDateAwal.toString().split(' ')[0];
ctrlTglAwal.text = formattedDate;
tglAwal.value = selectedDateAwal;
tglAwalTmp.value = selectedDateAwal.toString();
}
if (selectedDateAwal == null) {
print('cancel button');
return;
}
},
if (selectedDateAwal == null) {
print('cancel button');
return;
}
}
: null,
),
),
],

View File

@@ -2,7 +2,6 @@ import 'dart:convert';
import 'dart:io' as io;
import 'dart:io';
import 'package:app_petty_cash/app/app_extension.dart';
import 'package:app_petty_cash/app/route.dart';
import 'package:app_petty_cash/model/list_type_model.dart';
import 'package:app_petty_cash/screen/transaksi/insert_transaksi_provider.dart';
@@ -11,7 +10,6 @@ import 'package:app_petty_cash/screen/transaksi/list_type_provider.dart';
import 'package:app_petty_cash/screen/transaksi/transaksi_pick_date_widget.dart';
import 'package:app_petty_cash/screen/transaksi/transaksi_select_kategori_widget.dart';
import 'package:app_petty_cash/screen/transaksi/transaksi_upload_area_widget.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -19,14 +17,12 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:mime/mime.dart';
import '../../app/constant.dart';
import '../../model/list_category_model.dart';
import '../../provider/current_user_provider.dart';
import '../../widget/custom_drawer.dart';
import '../../widget/sankbar_widget.dart';
import '../login/custom_text_field.dart';
class DummyDropdownTipe {
final String options;
@@ -58,6 +54,8 @@ class TransaksiScreen extends HookConsumerWidget {
final fileDataBase64 = useState<String>("");
final isImage = useState(false);
final fileEkstension = useState("");
final fileSize = useState(0);
final fileName = useState("");
String formattedDate = DateFormat('dd-MM-yyyy').format(DateTime.now());
@@ -200,15 +198,16 @@ class TransaksiScreen extends HookConsumerWidget {
// List<int> imageBytes = await fileData.value?.readAsBytes();
if (fileData.value != null) {
final bytes = io.File(fileData.value!.path).readAsBytesSync();
String base64Image = base64Encode(bytes);
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(base64Image);
print(fileDataBase64.value);
}
}
@@ -218,13 +217,25 @@ class TransaksiScreen extends HookConsumerWidget {
source: ImageSource.camera,
);
if (pickedFile != null) {
final tmpFile = FilePickerResult([
PlatformFile(
name: pickedFile.name,
size: await pickedFile.length(),
path: pickedFile.path,
)
]);
if (await pickedFile.length() > 10000000) {
SanckbarWidget(context, "File tidak boleh lebih dari 10 MB",
snackbarType.warning);
} else {
fileData.value = pickedFile;
isImage.value = true;
fileEkstension.value = tmpFile.files.single.extension ?? "";
DateTime now = new DateTime.now();
fileName.value =
"IMG-${now.year}${now.month}${now.day}.${tmpFile.files.single.extension ?? ''}";
}
// final Directory appDocumentsDir =
// await getApplicationDocumentsDirectory();
// print(appDocumentsDir);
@@ -269,13 +280,14 @@ class TransaksiScreen extends HookConsumerWidget {
SanckbarWidget(context, "File tidak boleh lebih dari 10 MB",
snackbarType.warning);
} else {
File files = File(result.files.single.path!);
// File files = File(result.files.single.path!);
print(result.files.single.extension);
XFile fl = XFile(result.files.single.path!);
fileName.value = result.files.single.name;
isImage.value = imgExt.contains(result.files.single.extension);
print("ini xfile");
print(result.files.single.name);
fileData.value = fl;
await getBase64();
fileEkstension.value = result.files.single.extension ?? "";
@@ -285,6 +297,69 @@ class TransaksiScreen extends HookConsumerWidget {
}
}
insertTransaksi() {
if (selectedListTypeData.value.typeid.toString() == "DEBIT") {
ctrlNamaPengirim.text = "";
// validasi form
if (ctrlJumlah.text.isEmpty || ctrlCatatan.text.trim().isEmpty) {
SanckbarWidget(
context, "Jumlah dan catatan harus diisi", snackbarType.warning);
return;
}
} else {
if (selectedListTypeData.value.typeid.toString() == "KREDIT") {
selectedListCategory.value.categoryid = "0";
// validasi form
if (ctrlNamaPengirim.text.trim().isEmpty ||
ctrlJumlah.text.isEmpty ||
ctrlCatatan.text.trim().isEmpty) {
SanckbarWidget(
context,
"Nama pengirim, jumlah dan catatan harus diisi",
snackbarType.warning);
return;
}
}
}
DateTime parsedDate = DateFormat('dd-MM-yyyy').parse(
ctrlTglAwal.value.text.toString(),
);
String formattedDateTransaksi =
DateFormat('yyyy-MM-dd').format(parsedDate);
var param = {
"tgltransaksi": formattedDateTransaksi,
"typeid": selectedListTypeData.value.typeid.toString(),
"categoryid": selectedListCategory.value.categoryid.toString(),
"jumlah": ctrlJumlah.value.text.toString(),
"catatan": ctrlCatatan.value.text.toString(),
// "userid": "1",
"userid": userIDLogin,
"namapengirim": ctrlNamaPengirim.value.text.toString(),
"url": "",
// "base64file": fileDataBase64.value,
"fileName": fileName.value,
"fileExtension": fileEkstension.value,
"fileSize": fileSize.value.toString()
};
print(param);
// return;
ref.read(insertTransaksiProvider.notifier).insertTransaksi(
tanggal: formattedDateTransaksi,
tipe: selectedListTypeData.value.typeid.toString(),
kategoriid: selectedListCategory.value.categoryid.toString(),
jumlah: ctrlJumlah.value.text.toString(),
catatan: ctrlCatatan.value.text.toString(),
// "1",
userid: userIDLogin,
sender: ctrlNamaPengirim.value.text.toString(),
url: "",
base64file: fileDataBase64.value,
fileName: fileData.value?.name ?? "",
fileExtension: fileEkstension.value,
fileSize: fileSize.value.toString());
}
return Padding(
padding: EdgeInsets.only(
top: Constant.getActualYPhone(context: context, y: 30),
@@ -307,7 +382,7 @@ class TransaksiScreen extends HookConsumerWidget {
child: Padding(
padding: EdgeInsets.all(20),
child: Container(
height: MediaQuery.of(context).size.height - 10,
// height: MediaQuery.of(context).size.height - 10,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -363,9 +438,11 @@ class TransaksiScreen extends HookConsumerWidget {
),
// Tanggal Transaksi
TransaksiPickDateWidget(
ctrlTglAwal: ctrlTglAwal,
tglAwal: tglAwal,
tglAwalTmp: tglAwalTmp),
ctrlTglAwal: ctrlTglAwal,
tglAwal: tglAwal,
tglAwalTmp: tglAwalTmp,
isLoading: transaksiIsLoading,
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 20),
@@ -413,14 +490,16 @@ class TransaksiScreen extends HookConsumerWidget {
value: listTypeData.value[i],
groupValue:
selectedListTypeData.value,
onChanged: (ListType? index) {
if (isMounted()) {
selectedListTypeData.value =
index!;
} else {
return;
}
},
onChanged: !transaksiIsLoading.value
? (ListType? index) {
if (isMounted()) {
selectedListTypeData
.value = index!;
} else {
return;
}
}
: null,
),
Text(
listTypeData.value[i].typename ??
@@ -468,6 +547,7 @@ class TransaksiScreen extends HookConsumerWidget {
),
)
: TransaksiSelectKategoriWidget(
isLoading: transaksiIsLoading,
listCategoryData: listCategoryData,
selectedListCategory: selectedListCategory),
@@ -491,6 +571,7 @@ class TransaksiScreen extends HookConsumerWidget {
),
TextField(
controller: ctrlNamaPengirim,
readOnly: transaksiIsLoading.value,
decoration: InputDecoration(
hintStyle:
Constant.body2_400(context: context).copyWith(
@@ -534,6 +615,7 @@ class TransaksiScreen extends HookConsumerWidget {
TextField(
controller: ctrlJumlah,
keyboardType: TextInputType.number,
readOnly: transaksiIsLoading.value,
decoration: InputDecoration(
hintStyle:
Constant.body2_400(context: context).copyWith(
@@ -576,6 +658,7 @@ class TransaksiScreen extends HookConsumerWidget {
),
TextField(
readOnly: transaksiIsLoading.value,
controller: ctrlCatatan,
maxLines: 4,
decoration: InputDecoration(
@@ -610,6 +693,7 @@ class TransaksiScreen extends HookConsumerWidget {
// Upload File
TransaksiUploadAreaWidget(
isLoading: transaksiIsLoading,
isImage: isImage,
fileData: fileData,
fileDataBase64: fileDataBase64,
@@ -619,7 +703,11 @@ class TransaksiScreen extends HookConsumerWidget {
// Spacer(),
Container(
margin: EdgeInsets.only(
top: Constant.getActualYPhone(
context: context, y: 24)),
width: Constant.getActualXPhone(context: context, x: 390),
height: Constant.getActualY(context: context, y: 64),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateColor.resolveWith(
@@ -642,7 +730,7 @@ class TransaksiScreen extends HookConsumerWidget {
(transaksiIsLoading.value)
? SizedBox(
width: Constant.getActualXPhone(
context: context, x: 24),
context: context, x: 32),
height: Constant.getActualYPhone(
context: context, y: 32),
child: CircularProgressIndicator(
@@ -658,54 +746,12 @@ class TransaksiScreen extends HookConsumerWidget {
),
],
),
onPressed: () {
if (selectedListTypeData.value.typeid.toString() ==
"DEBIT") {
ctrlNamaPengirim.text = "";
// validasi form
} else {
if (selectedListTypeData.value.typeid.toString() ==
"KREDIT") {
selectedListCategory.value.categoryid = "0";
// validasi form
}
}
DateTime parsedDate = DateFormat('dd-MM-yyyy').parse(
ctrlTglAwal.value.text.toString(),
);
String formattedDateTransaksi =
DateFormat('yyyy-MM-dd').format(parsedDate);
var param = {
"tgltransaksi": formattedDateTransaksi,
"typeid":
selectedListTypeData.value.typeid.toString(),
"categoryid": selectedListCategory.value.categoryid
.toString(),
"jumlah": ctrlJumlah.value.text.toString(),
"catatan": ctrlCatatan.value.text.toString(),
// "userid": "1",
"userid": userIDLogin,
"namapengirim":
ctrlNamaPengirim.value.text.toString(),
"url": "",
};
print(param);
ref
.read(insertTransaksiProvider.notifier)
.insertTransaksi(
formattedDateTransaksi,
selectedListTypeData.value.typeid.toString(),
selectedListCategory.value.categoryid
.toString(),
ctrlJumlah.value.text.toString(),
ctrlCatatan.value.text.toString(),
// "1",
userIDLogin,
ctrlNamaPengirim.value.text.toString(),
"",
);
},
onPressed: !transaksiIsLoading.value
? () {
// transaksiIsLoading.value = true;
insertTransaksi();
}
: null,
),
),
],

View File

@@ -8,10 +8,12 @@ class TransaksiSelectKategoriWidget extends StatelessWidget {
super.key,
required this.listCategoryData,
required this.selectedListCategory,
required this.isLoading,
});
final ValueNotifier<List<ListCategory>> listCategoryData;
final ValueNotifier<ListCategory> selectedListCategory;
final ValueNotifier<bool> isLoading;
@override
Widget build(BuildContext context) {
@@ -45,12 +47,14 @@ class TransaksiSelectKategoriWidget extends StatelessWidget {
style: Constant.body1(context: context)
.copyWith(color: Constant.textBlack, fontWeight: FontWeight.w400),
value: selectedListCategory.value,
onChanged: (ListCategory? newValue) {
// if (newValue) {
selectedListCategory.value = newValue!;
print(selectedListCategory.value.categoryid);
// }
},
onChanged: !isLoading.value
? (ListCategory? newValue) {
// if (newValue) {
selectedListCategory.value = newValue!;
print(selectedListCategory.value.categoryid);
// }
}
: null,
buttonStyleData: ButtonStyleData(
height: Constant.getActualY(context: context, y: 80),
width: Constant.getActualX(context: context, x: 320),

View File

@@ -13,9 +13,11 @@ class TransaksiUploadAreaWidget extends StatelessWidget {
required this.fileDataBase64,
required this.pickFile,
required this.pickImage,
required this.isLoading,
});
final ValueNotifier<bool> isImage;
final ValueNotifier<bool> isLoading;
final ValueNotifier<XFile?> fileData;
final ValueNotifier<String> fileDataBase64;
final Function pickImage;
@@ -24,60 +26,63 @@ class TransaksiUploadAreaWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
print("tapped");
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: Constant.getActualY(context: context, y: 200),
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
pickFile();
},
icon: Icon(
Icons.folder_copy_rounded,
size: 50,
color: Constant.pcBtnBackgroundColor,
)),
Text("Browse a file",
style: Constant.body1(context: context).copyWith(
fontWeight: FontWeight.w600,
color: Constant.textBlack))
],
),
Column(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
pickImage();
},
icon: Icon(
Icons.add_a_photo_rounded,
size: 50,
color: Constant.pcBtnBackgroundColor,
)),
Text("Take a picture",
style: Constant.body1(context: context).copyWith(
fontWeight: FontWeight.w600,
color: Constant.textBlack))
],
),
],
),
);
},
);
},
onTap: !isLoading.value
? () {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: Constant.getActualY(context: context, y: 200),
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
pickFile();
},
icon: Icon(
Icons.folder_copy_rounded,
size: 50,
color: Constant.pcBtnBackgroundColor,
)),
Text("Browse a file",
style: Constant.body1(context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.textBlack))
],
),
Column(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
pickImage();
},
icon: Icon(
Icons.add_a_photo_rounded,
size: 50,
color: Constant.pcBtnBackgroundColor,
)),
Text("Take a picture",
style: Constant.body1(context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.textBlack))
],
),
],
),
);
},
);
}
: null,
child: Stack(
alignment: AlignmentDirectional.topEnd,
children: [
@@ -147,7 +152,7 @@ class TransaksiUploadAreaWidget extends StatelessWidget {
)));
}),
),
if (fileData.value != null)
if (fileData.value != null && !isLoading.value)
IconButton(
onPressed: () {
fileData.value = null;