segini dulu lah input file

This commit is contained in:
Golek 2022-12-07 15:58:09 +07:00
parent 521c54dfa8
commit abbd0d8cc8
5 changed files with 40 additions and 79 deletions

View File

@ -12,7 +12,7 @@ import '_dashed_rect.dart';
class InputFile extends StatefulWidget {
const InputFile({
Key? key,
this.files = const [],
this.files,
required this.onChange,
this.allowMultiple = false,
this.allowedExtensions = const ['jpg', 'jpeg', 'png', 'gif'],
@ -24,7 +24,7 @@ class InputFile extends StatefulWidget {
this.errorMessage,
}) : super(key: key);
final List<File> files;
final List<File>? files;
final void Function(List<File> files) onChange;
final bool? allowMultiple;
final List<String>? allowedExtensions;
@ -41,37 +41,27 @@ class InputFile extends StatefulWidget {
class _InputFileState extends State<InputFile> {
List<File> files = [];
StreamController<List<File>> controller = StreamController();
late Stream<List<File>> stream;
void addFileToSink(List<File> addedFile) {
controller.sink.add(files);
files = addedFile;
widget.onChange.call(files);
}
void removeFile(File file) {
setState(() {
files.removeAt(files.indexOf(file));
controller.sink.add(files);
}
void close() {
controller.close();
widget.onChange.call(files);
});
}
@override
void initState() {
super.initState();
// tambahkan initial component file value
files = widget.files;
if (widget.files != null) {
files = widget.files!;
addFileToSink(files);
// dapatkan stream dan listen ke onchange
stream = controller.stream;
}
@override
void dispose() {
close();
super.dispose();
}
/// ketika user memilih menggunakan camera saat input file
@ -121,8 +111,7 @@ class _InputFileState extends State<InputFile> {
Widget build(BuildContext context) {
final theme = GolekTheme.of(context);
print("INPUT FILE");
print(widget.isError!);
print(widget.isTouched!);
print(files);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -147,11 +136,7 @@ class _InputFileState extends State<InputFile> {
children: [
const SizedBox(height: 21),
OutlinedButton(
onPressed: () {
setState(() {
});
showModalFileToPick(
onPressed: () => showModalFileToPick(
context: context,
onPickCamera: (context) async {
await pickFileFromCamera(context);
@ -161,8 +146,7 @@ class _InputFileState extends State<InputFile> {
await pickFileFromGallery(context);
Navigator.of(context).pop();
},
);
},
),
style: OutlinedButton.styleFrom(
side: BorderSide(
width: 1,
@ -181,16 +165,10 @@ class _InputFileState extends State<InputFile> {
),
),
),
StreamBuilder(
stream: stream,
builder: (context, snapshot) {
widget.onChange.call(files);
return ListFilesBuilder(
ListFilesBuilder(
files: files,
multiple: widget.allowMultiple!,
onRemoveFile: removeFile,
);
},
),
const SizedBox(height: 5),
Text(

View File

@ -27,17 +27,16 @@ class _LandingPageState extends State<LandingPage> {
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = GolekTheme.of(context);
final form = FormGroup({
'foto': FormControl<List<File>>(
'file_pem': FormControl<List<File>>(
value: [],
validators: [requiredFile],
),
});
@override
Widget build(BuildContext context) {
final theme = GolekTheme.of(context);
return Scaffold(
appBar: LandingAppBar(),
body: SafeArea(
@ -46,25 +45,22 @@ class _LandingPageState extends State<LandingPage> {
child: Column(
children: [
ReactiveValueListenableBuilder(
formControlName: 'foto',
formControlName: 'file_pem',
builder: (context, control, child) {
print('DEBUG DI VALUE LISTEN');
print(control.value);
print(control.touched);
print(control.errors.entries);
return Container();
},
),
ReactiveInputFile(
name: 'foto',
name: 'file_pem',
allowMultiple: true,
),
ElevatedButton(
onPressed: () {
form.markAllAsTouched();
print(form.control('foto').hasErrors);
print(form.control('foto').errors);
print(form.control('foto').touched);
print(form.control('file_pem').value);
print(form.control('file_pem').hasErrors);
print(form.control('file_pem').errors);
print(form.control('file_pem').touched);
if (form.valid){
print("FORM IS VALID");
}

View File

@ -12,20 +12,14 @@ class ErrorMessages {
Map<String, String>? widgetCustomMessages,
}) {
Map<String, Object>? mergedErrorMessages = {
...?widgetCustomMessages,
...messages,
...?widgetCustomMessages,
};
MapEntry<String, dynamic> message = const MapEntry('', '');
print('GET UI ERROR ');
print(control.errors);
if (control.errors.entries.isNotEmpty) {
message = mergedErrorMessages.entries.firstWhere(
(element) => element.key == control.errors.entries.first.key,
final message = mergedErrorMessages.entries.firstWhere(
(element) => control.errors.entries.isNotEmpty && element.key == control.errors.entries.first.key,
orElse: () => const MapEntry('', ''),
);
}
return message.value.toString().replaceFirst('{_field_}', label);
}
}

View File

@ -1,13 +1,11 @@
import 'dart:io';
import 'package:component_library/component_library.dart';
import 'package:flutter/material.dart';
import 'package:reactive_forms/reactive_forms.dart';
import 'error_messages.dart';
class ReactiveInputFile extends ReactiveFormField<List<File>, List<File>> {
ReactiveInputFile({
required String name,
allowMultiple = false,
@ -19,7 +17,7 @@ class ReactiveInputFile extends ReactiveFormField<List<File>, List<File>> {
formControlName: name,
builder: (field) {
return InputFile(
files: field.value ?? [],
files: field.value,
allowMultiple: allowMultiple,
descriptionLabel: descriptionLabel,
guidanceLabel: guidanceLabel,
@ -28,16 +26,11 @@ class ReactiveInputFile extends ReactiveFormField<List<File>, List<File>> {
errorMessage: ErrorMessages.getUiErrorMessage(
control: field.control,
label: '',
widgetCustomMessages: {
'requiredFile': 'Foto harus diisi'
}
widgetCustomMessages: {'required': 'Foto harus diisi'},
),
isTouched: field.control.touched,
isError: field.control.hasErrors,
onChange: (files) {
print('ON CAHNEF');
print(field.control.touched);
print(field.control.hasErrors);
field.didChange(files);
},
);

View File

@ -3,5 +3,5 @@ import 'package:reactive_forms/reactive_forms.dart';
Map<String, dynamic>? requiredFile(AbstractControl<dynamic> control) {
return control.isNotNull && control.value?.isNotEmpty == true
? null
: {'requiredFile': true};
: {'required': true};
}