Compare commits
5 Commits
157ad9a34c
...
andy/coba-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
050f5f25e2 | ||
|
|
8e15f91b33 | ||
|
|
73cbde7f3e | ||
|
|
01d4560df1 | ||
|
|
532a341cec |
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import 'package:app_petty_cash/app/constant.dart';
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
|
||||||
|
final TextEditingController ctrlTglAwal;
|
||||||
|
final ValueNotifier<DateTime> tglAwal;
|
||||||
|
final ValueNotifier<String> tglAwalTmp;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
readOnly: true,
|
||||||
|
controller: ctrlTglAwal,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
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: "Tanggal Awal",
|
||||||
|
hintText: 'Tanggal Transaksi',
|
||||||
|
// suffixIcon: isLoadingFilterScope.value
|
||||||
|
// ? SizedBox(
|
||||||
|
// width: Constant.getActualXPhone(
|
||||||
|
// context: context,
|
||||||
|
// x: 4,
|
||||||
|
// ),
|
||||||
|
// height: Constant.getActualYPhone(
|
||||||
|
// context: context,
|
||||||
|
// y: 4,
|
||||||
|
// ),
|
||||||
|
// child: CircularProgressIndicator(
|
||||||
|
// color: Constant.textRed,
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// : Icon(
|
||||||
|
// Icons.calendar_month_sharp,
|
||||||
|
// 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),
|
||||||
|
|
||||||
|
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) {
|
||||||
|
print('cancel button');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,25 @@
|
|||||||
|
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/app_extension.dart';
|
||||||
import 'package:app_petty_cash/app/route.dart';
|
import 'package:app_petty_cash/app/route.dart';
|
||||||
import 'package:app_petty_cash/model/list_type_model.dart';
|
import 'package:app_petty_cash/model/list_type_model.dart';
|
||||||
import 'package:app_petty_cash/screen/transaksi/insert_transaksi_provider.dart';
|
import 'package:app_petty_cash/screen/transaksi/insert_transaksi_provider.dart';
|
||||||
import 'package:app_petty_cash/screen/transaksi/list_category_provider.dart';
|
import 'package:app_petty_cash/screen/transaksi/list_category_provider.dart';
|
||||||
import 'package:app_petty_cash/screen/transaksi/list_type_provider.dart';
|
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:dropdown_button2/dropdown_button2.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.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:image_picker/image_picker.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:mime/mime.dart';
|
||||||
|
|
||||||
import '../../app/constant.dart';
|
import '../../app/constant.dart';
|
||||||
import '../../model/list_category_model.dart';
|
import '../../model/list_category_model.dart';
|
||||||
@@ -43,6 +53,10 @@ class TransaksiScreen extends HookConsumerWidget {
|
|||||||
final ctrlJumlah = useTextEditingController(text: "");
|
final ctrlJumlah = useTextEditingController(text: "");
|
||||||
final ctrlCatatan = useTextEditingController(text: "");
|
final ctrlCatatan = useTextEditingController(text: "");
|
||||||
final ctrlNamaPengirim = useTextEditingController(text: "");
|
final ctrlNamaPengirim = useTextEditingController(text: "");
|
||||||
|
final fileData = useState<XFile?>(null);
|
||||||
|
final fileDataBase64 = useState<String>("");
|
||||||
|
final isImage = useState(false);
|
||||||
|
final fileEkstension = useState("");
|
||||||
|
|
||||||
String formattedDate = DateFormat('dd-MM-yyyy').format(DateTime.now());
|
String formattedDate = DateFormat('dd-MM-yyyy').format(DateTime.now());
|
||||||
|
|
||||||
@@ -178,6 +192,95 @@ class TransaksiScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
final userIDLogin = ref.read(currentUserProvider)?.model.M_UserID ?? "0";
|
final userIDLogin = ref.read(currentUserProvider)?.model.M_UserID ?? "0";
|
||||||
|
|
||||||
|
getBase64() async {
|
||||||
|
// List<int> imageBytes = await fileData.value?.readAsBytes();
|
||||||
|
if (fileData.value != null) {
|
||||||
|
final bytes = io.File(fileData.value!.path).readAsBytesSync();
|
||||||
|
String base64Image = base64Encode(bytes);
|
||||||
|
fileDataBase64.value = base64Image;
|
||||||
|
final file = File(fileData.value!.path);
|
||||||
|
print(file.lengthSync() / 1000000);
|
||||||
|
print(await fileData.value!.length());
|
||||||
|
|
||||||
|
// await getExternalStorageDirectory();
|
||||||
|
// print(await fileData.value!.saveTo(path));
|
||||||
|
print(base64Image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final ImagePicker _picker = ImagePicker();
|
||||||
|
pickImage() async {
|
||||||
|
final XFile? pickedFile = await _picker.pickImage(
|
||||||
|
source: ImageSource.camera,
|
||||||
|
);
|
||||||
|
if (pickedFile != null) {
|
||||||
|
if (await pickedFile.length() > 10000000) {
|
||||||
|
SanckbarWidget(context, "File tidak boleh lebih dari 10 MB",
|
||||||
|
snackbarType.warning);
|
||||||
|
} else {
|
||||||
|
fileData.value = pickedFile;
|
||||||
|
isImage.value = true;
|
||||||
|
}
|
||||||
|
// final Directory appDocumentsDir =
|
||||||
|
// await getApplicationDocumentsDirectory();
|
||||||
|
// print(appDocumentsDir);
|
||||||
|
// await pickedFile!.saveTo(appDocumentsDir.path);
|
||||||
|
await getBase64();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
browseImage() async {
|
||||||
|
final XFile? pickedFile = await _picker.pickImage(
|
||||||
|
source: ImageSource.gallery,
|
||||||
|
);
|
||||||
|
fileData.value = pickedFile;
|
||||||
|
getBase64();
|
||||||
|
}
|
||||||
|
|
||||||
|
pickFile() async {
|
||||||
|
List<String> imgExt = [
|
||||||
|
'jpg',
|
||||||
|
'png',
|
||||||
|
'jpeg',
|
||||||
|
];
|
||||||
|
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||||
|
allowMultiple: false,
|
||||||
|
type: FileType.custom,
|
||||||
|
dialogTitle: "Pick a file",
|
||||||
|
allowedExtensions: [
|
||||||
|
...imgExt,
|
||||||
|
'pdf',
|
||||||
|
'doc',
|
||||||
|
'docx',
|
||||||
|
'xls',
|
||||||
|
'xlsx',
|
||||||
|
'ppt',
|
||||||
|
'pptx',
|
||||||
|
'txt'
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
if (result.files.single.size > 10000000) {
|
||||||
|
SanckbarWidget(context, "File tidak boleh lebih dari 10 MB",
|
||||||
|
snackbarType.warning);
|
||||||
|
} else {
|
||||||
|
File files = File(result.files.single.path!);
|
||||||
|
print(result.files.single.extension);
|
||||||
|
XFile fl = XFile(result.files.single.path!);
|
||||||
|
|
||||||
|
isImage.value = imgExt.contains(result.files.single.extension);
|
||||||
|
|
||||||
|
print("ini xfile");
|
||||||
|
fileData.value = fl;
|
||||||
|
await getBase64();
|
||||||
|
fileEkstension.value = result.files.single.extension ?? "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// User canceled the picker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: Constant.getActualYPhone(context: context, y: 30),
|
top: Constant.getActualYPhone(context: context, y: 30),
|
||||||
@@ -211,87 +314,10 @@ class TransaksiScreen extends HookConsumerWidget {
|
|||||||
height: Constant.getActualYPhone(context: context, y: 10),
|
height: Constant.getActualYPhone(context: context, y: 10),
|
||||||
),
|
),
|
||||||
// Tanggal Transaksi
|
// Tanggal Transaksi
|
||||||
Row(
|
TransaksiPickDateWidget(
|
||||||
children: [
|
ctrlTglAwal: ctrlTglAwal,
|
||||||
Expanded(
|
tglAwal: tglAwal,
|
||||||
child: TextField(
|
tglAwalTmp: tglAwalTmp),
|
||||||
controller: ctrlTglAwal,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
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: "Tanggal Awal",
|
|
||||||
hintText: 'Tanggal Transaksi',
|
|
||||||
// suffixIcon: isLoadingFilterScope.value
|
|
||||||
// ? SizedBox(
|
|
||||||
// width: Constant.getActualXPhone(
|
|
||||||
// context: context,
|
|
||||||
// x: 4,
|
|
||||||
// ),
|
|
||||||
// height: Constant.getActualYPhone(
|
|
||||||
// context: context,
|
|
||||||
// y: 4,
|
|
||||||
// ),
|
|
||||||
// child: CircularProgressIndicator(
|
|
||||||
// color: Constant.textRed,
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
// : Icon(
|
|
||||||
// Icons.calendar_month_sharp,
|
|
||||||
// color: Constant.colorIconDate,
|
|
||||||
// ),
|
|
||||||
),
|
|
||||||
onTap: () async {
|
|
||||||
final selectedDateAwal = await showDatePicker(
|
|
||||||
// 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,
|
|
||||||
);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: Constant.getActualYPhone(context: context, y: 20),
|
height: Constant.getActualYPhone(context: context, y: 20),
|
||||||
@@ -390,124 +416,9 @@ class TransaksiScreen extends HookConsumerWidget {
|
|||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: SizedBox(
|
: TransaksiSelectKategoriWidget(
|
||||||
width: Constant.getActualXPhone(
|
listCategoryData: listCategoryData,
|
||||||
context: context, x: 390),
|
selectedListCategory: selectedListCategory),
|
||||||
child: DropdownButtonHideUnderline(
|
|
||||||
child: DropdownButton2<ListCategory>(
|
|
||||||
isExpanded: true,
|
|
||||||
hint: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
'Select Item',
|
|
||||||
style: Constant.body1(context: context)
|
|
||||||
.copyWith(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: Constant.textBlack),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
items: listCategoryData.value
|
|
||||||
.map((ListCategory option) {
|
|
||||||
return DropdownMenuItem<ListCategory>(
|
|
||||||
value: option,
|
|
||||||
child: Text(
|
|
||||||
option.categoryname ?? "",
|
|
||||||
style: Constant.body1(context: context)
|
|
||||||
.copyWith(
|
|
||||||
color: Constant.textBlack,
|
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
value: selectedListCategory.value,
|
|
||||||
onChanged: (ListCategory? newValue) {
|
|
||||||
// if (newValue) {
|
|
||||||
selectedListCategory.value = newValue!;
|
|
||||||
print(selectedListCategory.value.categoryid);
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
buttonStyleData: ButtonStyleData(
|
|
||||||
height: Constant.getActualY(
|
|
||||||
context: context, y: 56),
|
|
||||||
width: Constant.getActualX(
|
|
||||||
context: context, x: 320),
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
left: Constant.getActualX(
|
|
||||||
context: context, x: 10),
|
|
||||||
right: Constant.getActualX(
|
|
||||||
context: context, x: 10),
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Constant.white,
|
|
||||||
border: Border.all(
|
|
||||||
color: Constant.textBlack, width: 1),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
elevation: 2,
|
|
||||||
),
|
|
||||||
iconStyleData: IconStyleData(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.keyboard_arrow_down_outlined,
|
|
||||||
),
|
|
||||||
iconSize: 24,
|
|
||||||
iconEnabledColor: Constant.textBlack,
|
|
||||||
iconDisabledColor: Colors.grey,
|
|
||||||
),
|
|
||||||
dropdownStyleData: DropdownStyleData(
|
|
||||||
maxHeight: Constant.getActualY(
|
|
||||||
context: context, y: 200),
|
|
||||||
// width: Constant.getActualX(context: context, x: 320),
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
top: Constant.getActualY(
|
|
||||||
context: context, y: 10),
|
|
||||||
left: Constant.getActualX(
|
|
||||||
context: context, x: 10),
|
|
||||||
right: Constant.getActualX(
|
|
||||||
context: context, x: 10),
|
|
||||||
bottom: Constant.getActualY(
|
|
||||||
context: context, y: 10),
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Constant.white,
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.grey,
|
|
||||||
blurRadius: 20.0,
|
|
||||||
spreadRadius: 2.0,
|
|
||||||
offset: Offset(0.0, 0.0),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
elevation: 8,
|
|
||||||
offset: const Offset(0, -10),
|
|
||||||
scrollbarTheme: ScrollbarThemeData(
|
|
||||||
radius: const Radius.circular(40),
|
|
||||||
thickness:
|
|
||||||
MaterialStateProperty.all<double>(6),
|
|
||||||
thumbVisibility:
|
|
||||||
MaterialStateProperty.all<bool>(true),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
menuItemStyleData: MenuItemStyleData(
|
|
||||||
height: Constant.getActualY(
|
|
||||||
context: context, y: 56),
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
top: Constant.getActualY(
|
|
||||||
context: context, y: 10),
|
|
||||||
left: Constant.getActualX(
|
|
||||||
context: context, x: 10),
|
|
||||||
right: Constant.getActualX(
|
|
||||||
context: context, x: 10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: Constant.getActualYPhone(context: context, y: 20),
|
height: Constant.getActualYPhone(context: context, y: 20),
|
||||||
@@ -639,27 +550,12 @@ class TransaksiScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Upload File
|
// Upload File
|
||||||
Container(
|
TransaksiUploadAreaWidget(
|
||||||
width: Constant.getActualXPhone(context: context, x: 390),
|
isImage: isImage,
|
||||||
height: Constant.getActualYPhone(context: context, y: 83),
|
fileData: fileData,
|
||||||
decoration: BoxDecoration(color: Constant.bgUploadFile),
|
fileDataBase64: fileDataBase64,
|
||||||
child: Column(
|
pickFile: pickFile,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
pickImage: pickImage),
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.upload_outlined,
|
|
||||||
color: Constant.pcBtnBackgroundColor,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Upload File',
|
|
||||||
style: Constant.body1(context: context).copyWith(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: Constant.pcBtnBackgroundColor),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import 'package:app_petty_cash/app/constant.dart';
|
||||||
|
import 'package:app_petty_cash/model/list_category_model.dart';
|
||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TransaksiSelectKategoriWidget extends StatelessWidget {
|
||||||
|
const TransaksiSelectKategoriWidget({
|
||||||
|
super.key,
|
||||||
|
required this.listCategoryData,
|
||||||
|
required this.selectedListCategory,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ValueNotifier<List<ListCategory>> listCategoryData;
|
||||||
|
final ValueNotifier<ListCategory> selectedListCategory;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: Constant.getActualXPhone(context: context, x: 390),
|
||||||
|
child: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton2<ListCategory>(
|
||||||
|
isExpanded: true,
|
||||||
|
hint: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Select Item',
|
||||||
|
style: Constant.body1(context: context).copyWith(
|
||||||
|
fontWeight: FontWeight.w400, color: Constant.textBlack),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
items: listCategoryData.value.map((ListCategory option) {
|
||||||
|
return DropdownMenuItem<ListCategory>(
|
||||||
|
value: option,
|
||||||
|
child: Text(
|
||||||
|
option.categoryname ?? "",
|
||||||
|
style: Constant.body1(context: context).copyWith(
|
||||||
|
color: Constant.textBlack, fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
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);
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
buttonStyleData: ButtonStyleData(
|
||||||
|
height: Constant.getActualY(context: context, y: 80),
|
||||||
|
width: Constant.getActualX(context: context, x: 320),
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: Constant.getActualX(context: context, x: 20),
|
||||||
|
right: Constant.getActualX(context: context, x: 20),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Constant.white,
|
||||||
|
border: Border.all(color: Constant.textGrey, width: 1),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
// elevation: 2,
|
||||||
|
),
|
||||||
|
iconStyleData: IconStyleData(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.keyboard_arrow_down_outlined,
|
||||||
|
),
|
||||||
|
iconSize: 24,
|
||||||
|
iconEnabledColor: Constant.textBlack,
|
||||||
|
iconDisabledColor: Colors.grey,
|
||||||
|
),
|
||||||
|
dropdownStyleData: DropdownStyleData(
|
||||||
|
maxHeight: Constant.getActualY(context: context, y: 200),
|
||||||
|
// width: Constant.getActualX(context: context, x: 320),
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: Constant.getActualY(context: context, y: 10),
|
||||||
|
left: Constant.getActualX(context: context, x: 20),
|
||||||
|
right: Constant.getActualX(context: context, x: 20),
|
||||||
|
bottom: Constant.getActualY(context: context, y: 10),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Constant.white,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey,
|
||||||
|
blurRadius: 20.0,
|
||||||
|
spreadRadius: 2.0,
|
||||||
|
offset: Offset(0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
elevation: 8,
|
||||||
|
offset: const Offset(0, -10),
|
||||||
|
scrollbarTheme: ScrollbarThemeData(
|
||||||
|
radius: const Radius.circular(40),
|
||||||
|
thickness: MaterialStateProperty.all<double>(6),
|
||||||
|
thumbVisibility: MaterialStateProperty.all<bool>(true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
menuItemStyleData: MenuItemStyleData(
|
||||||
|
height: Constant.getActualY(context: context, y: 56),
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: Constant.getActualY(context: context, y: 10),
|
||||||
|
left: Constant.getActualX(context: context, x: 20),
|
||||||
|
right: Constant.getActualX(context: context, x: 20),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:app_petty_cash/app/constant.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:mime/mime.dart';
|
||||||
|
|
||||||
|
class TransaksiUploadAreaWidget extends StatelessWidget {
|
||||||
|
const TransaksiUploadAreaWidget({
|
||||||
|
super.key,
|
||||||
|
required this.isImage,
|
||||||
|
required this.fileData,
|
||||||
|
required this.fileDataBase64,
|
||||||
|
required this.pickFile,
|
||||||
|
required this.pickImage,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ValueNotifier<bool> isImage;
|
||||||
|
final ValueNotifier<XFile?> fileData;
|
||||||
|
final ValueNotifier<String> fileDataBase64;
|
||||||
|
final Function pickImage;
|
||||||
|
final Function pickFile;
|
||||||
|
|
||||||
|
@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))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Stack(
|
||||||
|
alignment: AlignmentDirectional.topEnd,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: Constant.getActualXPhone(context: context, x: 390),
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: isImage.value ? 200 : 83),
|
||||||
|
decoration: BoxDecoration(color: Constant.bgUploadFile),
|
||||||
|
child: Builder(builder: (context) {
|
||||||
|
final String? mime = lookupMimeType(fileData.value?.path ?? "");
|
||||||
|
return Semantics(
|
||||||
|
label: 'image_picker_example_picked_image',
|
||||||
|
child: (mime != null
|
||||||
|
? (mime.startsWith('image/'))
|
||||||
|
? Image.file(
|
||||||
|
// image: AssetImage(photo.value!.path),
|
||||||
|
File(fileData.value!.path),
|
||||||
|
frameBuilder: (context, child, frame,
|
||||||
|
wasSynchronouslyLoaded) {
|
||||||
|
return (wasSynchronouslyLoaded)
|
||||||
|
? Center(
|
||||||
|
child: Text("Loadinga"),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
errorBuilder: (BuildContext context, Object error,
|
||||||
|
StackTrace? stackTrace) {
|
||||||
|
return const Center(
|
||||||
|
child: Text(
|
||||||
|
'This image type is not supported'));
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.file_present_rounded,
|
||||||
|
size: 40,
|
||||||
|
color: Constant.pcBtnBackgroundColor,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
fileData.value?.name ?? '',
|
||||||
|
style: Constant.body2_400(context: context),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.upload_outlined,
|
||||||
|
color: Constant.pcBtnBackgroundColor,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Upload File',
|
||||||
|
style: Constant.body1(context: context).copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Constant.pcBtnBackgroundColor),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)));
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
if (fileData.value != null)
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
fileData.value = null;
|
||||||
|
fileDataBase64.value = '';
|
||||||
|
isImage.value = false;
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.cancel_outlined)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,8 +102,8 @@ class CustomDrawer extends HookConsumerWidget {
|
|||||||
// Handle navigation to Home screen
|
// Handle navigation to Home screen
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
ref.read(currentPageProvider.state).update((state) => 0);
|
ref.read(currentPageProvider.state).update((state) => 0);
|
||||||
// Navigator.pushNamed(context, homeRoute);
|
Navigator.pushNamed(context, homeRoute);
|
||||||
Navigator.pushNamed(context, cameraExampleRoute);
|
// Navigator.pushNamed(context, cameraExampleRoute);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
|||||||
Reference in New Issue
Block a user