From 06f9fca5baf5acae058e72f66733f2379155a18c Mon Sep 17 00:00:00 2001 From: akhaled Date: Sun, 16 Oct 2022 07:38:16 +0200 Subject: [PATCH 1/2] .. --- example/pubspec.lock | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index dd05718..c581ebd 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -21,21 +21,14 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "1.2.1" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: @@ -56,7 +49,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -94,28 +87,28 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" simple_json_form: dependency: "direct main" description: @@ -134,7 +127,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" stack_trace: dependency: transitive description: @@ -155,21 +148,21 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" vector_math: dependency: transitive description: From cb0536ca71ecd954df3fa62d3ea28aa7693c7a20 Mon Sep 17 00:00:00 2001 From: akhaled Date: Sun, 16 Oct 2022 07:47:19 +0200 Subject: [PATCH 2/2] solve keyboard issus , add primary color schema and isRTL flag for design --- .../simple_json_form_controller.dart | 115 +- lib/src/key/simple_json_form_key.dart | 43 +- lib/src/model/default_values.dart | 172 +-- lib/src/model/json_schema.dart | 487 ++++---- lib/src/model/raw_builder.dart | 57 +- lib/src/model/validation_schema.dart | 83 +- lib/src/theme/theme.dart | 2 +- lib/src/ui/simple_json_form.dart | 364 +++--- lib/src/ui/simple_json_form_view_model.dart | 40 +- lib/src/utils/constants.dart | 38 +- lib/src/utils/dialog_form.dart | 182 +-- lib/src/utils/form.dart | 136 +-- lib/src/utils/utils.dart | 18 +- lib/src/widgets/custom_dropdown_widget.dart | 230 ++-- lib/src/widgets/form_button.dart | 299 ++--- lib/src/widgets/input_label.dart | 61 +- lib/src/widgets/input_text.dart | 205 ++-- lib/src/widgets/primary_button.dart | 107 +- lib/src/widgets/secondary_button.dart | 100 +- lib/src/widgets/simple_json_form_field.dart | 1019 +++++++++-------- lib/src/widgets/simple_json_form_remark.dart | 66 +- lib/src/widgets/text_cfirst.dart | 60 +- lib/src/widgets/title_text.dart | 52 +- 23 files changed, 1993 insertions(+), 1943 deletions(-) diff --git a/lib/src/controller/simple_json_form_controller.dart b/lib/src/controller/simple_json_form_controller.dart index 45f3f65..ffe7dad 100644 --- a/lib/src/controller/simple_json_form_controller.dart +++ b/lib/src/controller/simple_json_form_controller.dart @@ -1,57 +1,58 @@ -import 'package:flutter/widgets.dart'; -import 'package:simple_json_form/simple_json_form.dart'; -import 'package:simple_json_form/src/model/raw_builder.dart'; - -class SimpleJsonFormController { - SimpleJsonFormController({required this.jsonSchema}) { - controllerMapping = generateKeyMapping(jsonSchema); - } - - final JsonSchema jsonSchema; - - static Map controllerMapping = {}; - - Map generateKeyMapping(JsonSchema jsonSchema) { - Map keyMapping = {}; - for (var entry in jsonSchema.form) { - for (Properties property in entry.properties ?? []) { - // if (property.remark) { - // keyMapping['${property.key}_remark'] = TextEditingController(); - // } - if (property.type == JsonSchemaType.format1) { - if (property.raw != null) { - final mapRaw = generateKeyMappingFormBuilder(property.raw!); - keyMapping.addAll(mapRaw); - } - } - - if (property.type == JsonSchemaType.text || - property.type == JsonSchemaType.number || - property.type == JsonSchemaType.date || - property.type == JsonSchemaType.time) { - keyMapping[property.key] = TextEditingController(); - } - } - } - return keyMapping; - } - - Map generateKeyMappingFormBuilder(List formBuilders) { - Map keyMapping = {}; - for (var entry in formBuilders) { - for (Properties property in entry.properties) { - if (property.type == JsonSchemaType.text || - property.type == JsonSchemaType.number || - property.type == JsonSchemaType.date || - property.type == JsonSchemaType.time) { - keyMapping[property.key] = TextEditingController(); - } - } - } - return keyMapping; - } - - static TextEditingController? getKeyController(String key) { - return controllerMapping.containsKey(key) ? controllerMapping[key] : null; - } -} +import 'package:flutter/widgets.dart'; +import 'package:simple_json_form/simple_json_form.dart'; +import 'package:simple_json_form/src/model/raw_builder.dart'; + +class SimpleJsonFormController { + SimpleJsonFormController({required this.jsonSchema}) { + controllerMapping = generateKeyMapping(jsonSchema); + } + + final JsonSchema jsonSchema; + + static Map controllerMapping = {}; + + Map generateKeyMapping(JsonSchema jsonSchema) { + Map keyMapping = {}; + for (var entry in jsonSchema.form) { + for (Properties property in entry.properties ?? []) { + // if (property.remark) { + // keyMapping['${property.key}_remark'] = TextEditingController(); + // } + if (property.type == JsonSchemaType.format1) { + if (property.raw != null) { + final mapRaw = generateKeyMappingFormBuilder(property.raw!); + keyMapping.addAll(mapRaw); + } + } + + if (property.type == JsonSchemaType.text || + property.type == JsonSchemaType.number || + property.type == JsonSchemaType.date || + property.type == JsonSchemaType.time) { + keyMapping[property.key] = TextEditingController(); + } + } + } + return keyMapping; + } + + Map generateKeyMappingFormBuilder( + List formBuilders) { + Map keyMapping = {}; + for (var entry in formBuilders) { + for (Properties property in entry.properties) { + if (property.type == JsonSchemaType.text || + property.type == JsonSchemaType.number || + property.type == JsonSchemaType.date || + property.type == JsonSchemaType.time) { + keyMapping[property.key] = TextEditingController(); + } + } + } + return keyMapping; + } + + static TextEditingController? getKeyController(String key) { + return controllerMapping.containsKey(key) ? controllerMapping[key] : null; + } +} diff --git a/lib/src/key/simple_json_form_key.dart b/lib/src/key/simple_json_form_key.dart index 60da2b4..32fd6d6 100644 --- a/lib/src/key/simple_json_form_key.dart +++ b/lib/src/key/simple_json_form_key.dart @@ -1,19 +1,24 @@ -import 'package:flutter/widgets.dart'; -import 'package:simple_json_form/simple_json_form.dart'; - -class SimpleJsonFormKey { - SimpleJsonFormKey({required this.jsonSchema}) { - keyMapping = generateKeyMapping(jsonSchema); - } - - final JsonSchema jsonSchema; - static Map> keyMapping = {}; - - Map> generateKeyMapping(JsonSchema jsonSchema) { - Map> keyMapping = {}; - for (var entry in jsonSchema.form) { - keyMapping[entry.key] = GlobalKey(); - } - return keyMapping; - } -} +import 'package:flutter/widgets.dart'; +import 'package:simple_json_form/simple_json_form.dart'; + +class SimpleJsonFormKey { + SimpleJsonFormKey({required this.jsonSchema}) { + keyMapping = generateKeyMapping(jsonSchema); + } + + final JsonSchema jsonSchema; + static Map> keyMapping = {}; + + Map> generateKeyMapping(JsonSchema jsonSchema) { + Map> keyMapping = {}; + for (var entry in jsonSchema.form) { + keyMapping[entry.key] = GlobalKey(); + } + return keyMapping; + } + + static final formKey = GlobalKey(); + static GlobalKey generateFormKeyMapping() { + return formKey; + } +} diff --git a/lib/src/model/default_values.dart b/lib/src/model/default_values.dart index 8b7468b..c2839ad 100644 --- a/lib/src/model/default_values.dart +++ b/lib/src/model/default_values.dart @@ -1,82 +1,90 @@ -import 'package:flutter/widgets.dart'; - -@immutable -class DefaultValues { - const DefaultValues.raw({ - required this.hintDropdownText, - required this.nextButtonText, - required this.previousButtonText, - required this.submitButtonText, - required this.validationDescription, - required this.validationTitle, - required this.fieldRequired, - }); - - factory DefaultValues({ - String? submitButtonText, - String? previousButtonText, - String? nextButtonText, - String? validationTitle, - String? validationDescription, - String? hintDropdownText, - String? fieldRequired, - }) { - submitButtonText = submitButtonText ??= 'Submit'; - previousButtonText = previousButtonText ??= 'Previous'; - nextButtonText = nextButtonText ??= 'nextButtonText'; - validationTitle = validationTitle ??= 'Failed validations'; - validationDescription = - validationDescription ??= 'Some fields require your validation'; - hintDropdownText = hintDropdownText ??= 'Select option'; - fieldRequired = fieldRequired ??= 'Field is required'; - return DefaultValues.raw( - hintDropdownText: hintDropdownText, - nextButtonText: nextButtonText, - previousButtonText: previousButtonText, - submitButtonText: submitButtonText, - validationDescription: validationDescription, - validationTitle: validationTitle, - fieldRequired: fieldRequired, - ); - } - - DefaultValues copyWith({ - String? submitButtonText, - String? previousButtonText, - String? nextButtonText, - String? validationTitle, - String? validationDescription, - String? hintDropdownText, - String? fieldRequired, - }) => - DefaultValues( - hintDropdownText: hintDropdownText ?? this.hintDropdownText, - nextButtonText: nextButtonText ?? this.nextButtonText, - previousButtonText: previousButtonText ?? this.previousButtonText, - submitButtonText: submitButtonText ?? this.submitButtonText, - validationDescription: - validationDescription ?? this.validationDescription, - validationTitle: validationTitle ?? this.validationTitle, - fieldRequired: fieldRequired ?? this.fieldRequired, - ); - - //To use for text the submit button - final String submitButtonText; - - //To use for text the previous button - final String previousButtonText; - - //To use for text the next button - final String nextButtonText; - - //text for use dialog info - final String validationTitle; - - //text for use dialog info - final String validationDescription; - - //hintDropdownText to use display hint dropdown in form - final String hintDropdownText; - - final String fieldRequired; -} +import 'package:flutter/widgets.dart'; + +@immutable +class DefaultValues { + const DefaultValues.raw({ + required this.hintDropdownText, + required this.nextButtonText, + required this.previousButtonText, + required this.submitButtonText, + required this.validationDescription, + required this.validationTitle, + required this.fieldRequired, + required this.isRTL, + }); + + factory DefaultValues({ + String? submitButtonText, + String? previousButtonText, + String? nextButtonText, + String? validationTitle, + String? validationDescription, + String? hintDropdownText, + String? fieldRequired, + bool? isRTL, + }) { + submitButtonText = submitButtonText ??= 'Submit'; + previousButtonText = previousButtonText ??= 'Previous'; + nextButtonText = nextButtonText ??= 'nextButtonText'; + validationTitle = validationTitle ??= 'Failed validations'; + validationDescription = + validationDescription ??= 'Some fields require your validation'; + hintDropdownText = hintDropdownText ??= 'Select option'; + fieldRequired = fieldRequired ??= 'Field is required'; + isRTL = isRTL ??= false; + return DefaultValues.raw( + hintDropdownText: hintDropdownText, + nextButtonText: nextButtonText, + previousButtonText: previousButtonText, + submitButtonText: submitButtonText, + validationDescription: validationDescription, + validationTitle: validationTitle, + fieldRequired: fieldRequired, + isRTL: isRTL, + ); + } + + DefaultValues copyWith({ + String? submitButtonText, + String? previousButtonText, + String? nextButtonText, + String? validationTitle, + String? validationDescription, + String? hintDropdownText, + String? fieldRequired, + bool? isRTL, + }) => + DefaultValues( + hintDropdownText: hintDropdownText ?? this.hintDropdownText, + nextButtonText: nextButtonText ?? this.nextButtonText, + previousButtonText: previousButtonText ?? this.previousButtonText, + submitButtonText: submitButtonText ?? this.submitButtonText, + validationDescription: + validationDescription ?? this.validationDescription, + validationTitle: validationTitle ?? this.validationTitle, + fieldRequired: fieldRequired ?? this.fieldRequired, + isRTL: isRTL ?? this.isRTL, + ); + + //To use for text the submit button + final String submitButtonText; + + //To use for text the previous button + final String previousButtonText; + + //To use for text the next button + final String nextButtonText; + + //text for use dialog info + final String validationTitle; + + //text for use dialog info + final String validationDescription; + + //hintDropdownText to use display hint dropdown in form + final String hintDropdownText; + + final String fieldRequired; + // isRTL used to handle rtl direction of widget + final bool isRTL; +} diff --git a/lib/src/model/json_schema.dart b/lib/src/model/json_schema.dart index f86f712..b25fa94 100644 --- a/lib/src/model/json_schema.dart +++ b/lib/src/model/json_schema.dart @@ -1,240 +1,247 @@ -import 'package:simple_json_form/src/controller/simple_json_form_controller.dart'; -import 'package:simple_json_form/src/key/simple_json_form_key.dart'; -import 'package:simple_json_form/src/model/raw_builder.dart'; -import 'package:simple_json_form/src/model/validation_schema.dart'; - -/// An instance has one of six primitive types, and a range of possible values depending on the type: -enum JsonSchemaType { - /// multiple: - /// A "true" or "false" value, from the JSON "true" or "false" value - multiple, - - /// checkbox: - /// An ordered list of instances, from the JSON "array" value - checkbox, - - /// dropdown: - /// An unordered set of properties mapping a string to an instance, from the JSON "object" value - dropdown, - - /// number: - /// An arbitrary-precision, base-10 decimal number value, from the JSON "number" value - number, - - /// dateTime: - /// A string of datetime - datetime, - - /// time: - /// A string of time - time, - - /// date: - /// A string of date - date, - - /// file: - /// A string of file - file, - - /// string: - /// A string of Unicode code points, from the JSON "string" value - text, - - /// Format 1 - /// Only Array of String dynamic value use field raw. - format1, - - /// SPECIAL_CASE_NONE: - /// A special case for when the type is not defined. - none, -} - -class JsonSchema { - final List form; - - JsonSchema({required this.form}); - - factory JsonSchema.fromJson(Map json) { - final jsonSchema = JsonSchema( - form: json['form'] == null - ? [] - : List.from( - json['form'].map( - (e) => FormBuilder.fromJson(e), - ), - ), - ); - SimpleJsonFormKey(jsonSchema: jsonSchema); - SimpleJsonFormController(jsonSchema: jsonSchema); - return jsonSchema; - } - - Map toJson() => {'form': form.map((v) => v.toJson()).toList()}; -} - -class FormBuilder { - final List? properties; - final String key; - //List? properties; - - FormBuilder({ - required this.key, - this.properties, - }); - - factory FormBuilder.fromJson(Map json) => FormBuilder( - key: json['key'], - properties: json['properties'] != null - ? List.from(json['properties'].map((e) => Properties.fromJson(e))) - : null, - ); - - Map toJson() => { - 'properties': properties == null ? [] : properties!.map((v) => v.toJson()).toList(), - }; -} - -class Properties { - Properties({ - required this.key, - required this.type, - required this.title, - required this.readOnly, - required this.isRequired, - this.raw, - this.description, - this.fields, - this.validations, - this.maxLine, - this.answer, - }); - - factory Properties.fromJson(Map json) => Properties( - fields: json.containsKey('fields') ? json['fields'].cast() : null, - key: json['key'], - title: json['title'], - description: json['description'], - type: stringToJsonSchemaType[json['type']] ?? JsonSchemaType.none, - maxLine: json["maxline"], - isRequired: json['is_mandatory'] ?? false, - readOnly: json['readOnly'] ?? false, - answer: json['type'] == "checkbox" - ? List.generate(json['fields'].cast().length, (index) => false) - : null, - validations: json['validations'] is Map - ? ValidationSchema.fromJSON(json['validations']) - : null, - raw: json.containsKey('raw') - ? List.from(json['raw'].map((el) => RawBuilder.fromJson(el))) - : null, - ); - - Map toJson() { - final Map data = {}; - data['fields'] = type == JsonSchemaType.text ? "300" : fields.toString(); - data['key'] = key; - data['title'] = title; - data['description'] = description; - data['type'] = type.toString(); - data['is_mandatory'] = isRequired; - data["maxline"] = maxLine; - data["answer"] = answer.toString(); - return data; - } - - Properties copyWith({ - String? key, - String? title, - String? description, - int? maxLine, - bool? readOnly, - bool? isRequired, - JsonSchemaType? type, - List? fields, - dynamic answer, - }) => - Properties( - answer: answer ?? this.answer, - description: description ?? this.description, - fields: fields ?? this.fields, - isRequired: isRequired ?? this.isRequired, - maxLine: maxLine ?? this.maxLine, - readOnly: readOnly ?? this.readOnly, - key: key ?? this.key, - title: title ?? this.title, - type: type ?? this.type, - ); - - /// A key for use controller and MUST be unique - final String key; - - /// A descriptive title of the element. - final String title; - - /// A long description of the element. Used in hover menus and suggestions. - final String? description; - - /// The value of this keyword MUST be either a string or an array. If it is an array, elements of the array MUST be strings and MUST be unique. - /// - /// String values MUST be one of the six primitive types ("null", "boolean", "object", "array", "number", or "string"), or "integer" which matches any number with a zero fractional part. - /// - /// An instance validates if and only if the instance is in any of the sets listed for this keyword. - final JsonSchemaType type; - - /// required - /// - /// The value MUST be strings. \ - final bool isRequired; - - /// The value of these keywords MUST be a boolean. When multiple occurrences \ - /// of these keywords are applicable to a single sub-instance, the resulting \ - /// behavior SHOULD be as for a true value if any occurrence specifies a true \ - /// value, and SHOULD be as for a false value otherwise. - /// - /// If "readOnly" has a value of boolean true, it indicates that the value of \ - /// the instance is managed exclusively by the owning authority, and attempts \ - /// by an application to modify the value of this property are expected to be \ - /// ignored or rejected by that owning authority. - final bool readOnly; - - /// The value MUST be int or null - /// Maxline use for input object - final int? maxLine; - - /// The value MUST be list of string or null - /// fields use for form type checkbox, option, and header formater - /// - final List? fields; - - //PUT OFF ==> - // final String? remarkLabel; - // final String? remarkTitle; - // final bool remark; - // String? remarkData; - //<== - - /// Validation - /// Object use for model validation - final ValidationSchema? validations; - - /// raw - /// Object use for model - final List? raw; - - dynamic answer; -} - -Map stringToJsonSchemaType = { - 'multiple': JsonSchemaType.multiple, - 'dropdown': JsonSchemaType.dropdown, - 'checkbox': JsonSchemaType.checkbox, - 'number': JsonSchemaType.number, - 'datetime': JsonSchemaType.datetime, - 'time': JsonSchemaType.time, - 'date': JsonSchemaType.date, - 'file': JsonSchemaType.file, - 'text': JsonSchemaType.text, - 'format1': JsonSchemaType.format1, - 'none': JsonSchemaType.none, -}; +import 'package:simple_json_form/src/controller/simple_json_form_controller.dart'; +import 'package:simple_json_form/src/key/simple_json_form_key.dart'; +import 'package:simple_json_form/src/model/raw_builder.dart'; +import 'package:simple_json_form/src/model/validation_schema.dart'; + +/// An instance has one of six primitive types, and a range of possible values depending on the type: +enum JsonSchemaType { + /// multiple: + /// A "true" or "false" value, from the JSON "true" or "false" value + multiple, + + /// checkbox: + /// An ordered list of instances, from the JSON "array" value + checkbox, + + /// dropdown: + /// An unordered set of properties mapping a string to an instance, from the JSON "object" value + dropdown, + + /// number: + /// An arbitrary-precision, base-10 decimal number value, from the JSON "number" value + number, + + /// dateTime: + /// A string of datetime + datetime, + + /// time: + /// A string of time + time, + + /// date: + /// A string of date + date, + + /// file: + /// A string of file + file, + + /// string: + /// A string of Unicode code points, from the JSON "string" value + text, + + /// Format 1 + /// Only Array of String dynamic value use field raw. + format1, + + /// SPECIAL_CASE_NONE: + /// A special case for when the type is not defined. + none, +} + +class JsonSchema { + final List form; + + JsonSchema({required this.form}); + + factory JsonSchema.fromJson(Map json) { + final jsonSchema = JsonSchema( + form: json['form'] == null + ? [] + : List.from( + json['form'].map( + (e) => FormBuilder.fromJson(e), + ), + ), + ); + SimpleJsonFormKey(jsonSchema: jsonSchema); + SimpleJsonFormController(jsonSchema: jsonSchema); + return jsonSchema; + } + + Map toJson() => + {'form': form.map((v) => v.toJson()).toList()}; +} + +class FormBuilder { + final List? properties; + final String key; + //List? properties; + + FormBuilder({ + required this.key, + this.properties, + }); + + factory FormBuilder.fromJson(Map json) => FormBuilder( + key: json['key'], + properties: json['properties'] != null + ? List.from( + json['properties'].map((e) => Properties.fromJson(e))) + : null, + ); + + Map toJson() => { + 'properties': properties == null + ? [] + : properties!.map((v) => v.toJson()).toList(), + }; +} + +class Properties { + Properties({ + required this.key, + required this.type, + required this.title, + required this.readOnly, + required this.isRequired, + this.raw, + this.description, + this.fields, + this.validations, + this.maxLine, + this.answer, + }); + + factory Properties.fromJson(Map json) => Properties( + fields: + json.containsKey('fields') ? json['fields'].cast() : null, + key: json['key'], + title: json['title'], + description: json['description'], + type: stringToJsonSchemaType[json['type']] ?? JsonSchemaType.none, + maxLine: json["maxline"], + isRequired: json['is_mandatory'] ?? false, + readOnly: json['readOnly'] ?? false, + answer: json['type'] == "checkbox" + ? List.generate( + json['fields'].cast().length, (index) => false) + : null, + validations: json['validations'] is Map + ? ValidationSchema.fromJSON(json['validations']) + : null, + raw: json.containsKey('raw') + ? List.from( + json['raw'].map((el) => RawBuilder.fromJson(el))) + : null, + ); + + Map toJson() { + final Map data = {}; + data['fields'] = type == JsonSchemaType.text ? "300" : fields.toString(); + data['key'] = key; + data['title'] = title; + data['description'] = description; + data['type'] = type.toString(); + data['is_mandatory'] = isRequired; + data["maxline"] = maxLine; + data["answer"] = answer.toString(); + return data; + } + + Properties copyWith({ + String? key, + String? title, + String? description, + int? maxLine, + bool? readOnly, + bool? isRequired, + JsonSchemaType? type, + List? fields, + dynamic answer, + }) => + Properties( + answer: answer ?? this.answer, + description: description ?? this.description, + fields: fields ?? this.fields, + isRequired: isRequired ?? this.isRequired, + maxLine: maxLine ?? this.maxLine, + readOnly: readOnly ?? this.readOnly, + key: key ?? this.key, + title: title ?? this.title, + type: type ?? this.type, + ); + + /// A key for use controller and MUST be unique + final String key; + + /// A descriptive title of the element. + final String title; + + /// A long description of the element. Used in hover menus and suggestions. + final String? description; + + /// The value of this keyword MUST be either a string or an array. If it is an array, elements of the array MUST be strings and MUST be unique. + /// + /// String values MUST be one of the six primitive types ("null", "boolean", "object", "array", "number", or "string"), or "integer" which matches any number with a zero fractional part. + /// + /// An instance validates if and only if the instance is in any of the sets listed for this keyword. + final JsonSchemaType type; + + /// required + /// + /// The value MUST be strings. \ + final bool isRequired; + + /// The value of these keywords MUST be a boolean. When multiple occurrences \ + /// of these keywords are applicable to a single sub-instance, the resulting \ + /// behavior SHOULD be as for a true value if any occurrence specifies a true \ + /// value, and SHOULD be as for a false value otherwise. + /// + /// If "readOnly" has a value of boolean true, it indicates that the value of \ + /// the instance is managed exclusively by the owning authority, and attempts \ + /// by an application to modify the value of this property are expected to be \ + /// ignored or rejected by that owning authority. + final bool readOnly; + + /// The value MUST be int or null + /// Maxline use for input object + final int? maxLine; + + /// The value MUST be list of string or null + /// fields use for form type checkbox, option, and header formater + /// + final List? fields; + + //PUT OFF ==> + // final String? remarkLabel; + // final String? remarkTitle; + // final bool remark; + // String? remarkData; + //<== + + /// Validation + /// Object use for model validation + final ValidationSchema? validations; + + /// raw + /// Object use for model + final List? raw; + + dynamic answer; +} + +Map stringToJsonSchemaType = { + 'multiple': JsonSchemaType.multiple, + 'dropdown': JsonSchemaType.dropdown, + 'checkbox': JsonSchemaType.checkbox, + 'number': JsonSchemaType.number, + 'datetime': JsonSchemaType.datetime, + 'time': JsonSchemaType.time, + 'date': JsonSchemaType.date, + 'file': JsonSchemaType.file, + 'text': JsonSchemaType.text, + 'format1': JsonSchemaType.format1, + 'none': JsonSchemaType.none, +}; diff --git a/lib/src/model/raw_builder.dart b/lib/src/model/raw_builder.dart index dfa862e..7d8cc42 100644 --- a/lib/src/model/raw_builder.dart +++ b/lib/src/model/raw_builder.dart @@ -1,28 +1,29 @@ -import 'package:simple_json_form/src/model/json_schema.dart'; - -class RawBuilder { - RawBuilder({ - required this.title, - required this.properties, - this.description, - }); - - factory RawBuilder.fromJson(Map json) => RawBuilder( - properties: List.from(json['properties'].map((e) => Properties.fromJson(e))), - title: json['title'], - description: json['description'], - ); - - Map toJson() => { - 'properties': properties.map((v) => v.toJson()).toList(), - }; - - ///List of properties - final List properties; - - /// Title format string - final String title; - - /// Description - final String? description; -} +import 'package:simple_json_form/src/model/json_schema.dart'; + +class RawBuilder { + RawBuilder({ + required this.title, + required this.properties, + this.description, + }); + + factory RawBuilder.fromJson(Map json) => RawBuilder( + properties: List.from( + json['properties'].map((e) => Properties.fromJson(e))), + title: json['title'], + description: json['description'], + ); + + Map toJson() => { + 'properties': properties.map((v) => v.toJson()).toList(), + }; + + ///List of properties + final List properties; + + /// Title format string + final String title; + + /// Description + final String? description; +} diff --git a/lib/src/model/validation_schema.dart b/lib/src/model/validation_schema.dart index e994c57..a397944 100644 --- a/lib/src/model/validation_schema.dart +++ b/lib/src/model/validation_schema.dart @@ -1,41 +1,42 @@ -class ValidationSchema { - final FormatType format; - final Length length; - final String message; - - ValidationSchema({ - required this.message, - required this.format, - required this.length, - }); - - factory ValidationSchema.fromJSON(Map json) => ValidationSchema( - length: Length.fromJSON(json['length'] ?? {}), - format: stringToFormatType[json['type']] ?? FormatType.none, - message: json['message'] ?? 'Field is required', - ); -} - -class Length { - final int max; - final int min; - - Length({ - required this.max, - required this.min, - }); - - factory Length.fromJSON(Map json) => Length( - max: json['max'] ?? 5, - min: json['min'] ?? 0, - ); -} - -enum FormatType { none, email, text, number } - -Map stringToFormatType = { - 'none': FormatType.none, - 'email': FormatType.email, - 'text': FormatType.text, - 'number': FormatType.number, -}; +class ValidationSchema { + final FormatType format; + final Length length; + final String message; + + ValidationSchema({ + required this.message, + required this.format, + required this.length, + }); + + factory ValidationSchema.fromJSON(Map json) => + ValidationSchema( + length: Length.fromJSON(json['length'] ?? {}), + format: stringToFormatType[json['type']] ?? FormatType.none, + message: json['message'] ?? 'Field is required', + ); +} + +class Length { + final int max; + final int min; + + Length({ + required this.max, + required this.min, + }); + + factory Length.fromJSON(Map json) => Length( + max: json['max'] ?? 5, + min: json['min'] ?? 0, + ); +} + +enum FormatType { none, email, text, number } + +Map stringToFormatType = { + 'none': FormatType.none, + 'email': FormatType.email, + 'text': FormatType.text, + 'number': FormatType.number, +}; diff --git a/lib/src/theme/theme.dart b/lib/src/theme/theme.dart index 8b13789..d3f5a12 100644 --- a/lib/src/theme/theme.dart +++ b/lib/src/theme/theme.dart @@ -1 +1 @@ - + diff --git a/lib/src/ui/simple_json_form.dart b/lib/src/ui/simple_json_form.dart index 0d0a9f5..a97fb1b 100644 --- a/lib/src/ui/simple_json_form.dart +++ b/lib/src/ui/simple_json_form.dart @@ -1,183 +1,181 @@ -import 'package:flutter/material.dart'; -import 'package:simple_json_form/simple_json_form.dart'; -import 'package:simple_json_form/src/key/simple_json_form_key.dart'; -import 'package:simple_json_form/src/utils/dialog_form.dart'; -import 'package:simple_json_form/src/widgets/form_button.dart'; -import 'package:simple_json_form/src/widgets/simple_json_form_field.dart'; - -class SimpleJsonForm extends StatefulWidget { - //JSON Schema to use to generate the form. - final JsonSchema jsonSchema; - - //crossAxisAlignment to use general form - final CrossAxisAlignment crossAxisAlignment; - - //padding to use general form - final EdgeInsetsGeometry? padding; - - //Title general to use the form - final String? title; - - //title style to use title the form - final TextStyle? titleStyle; - - //Description general to use the form - final String? description; - - //Description style to use description form - final TextStyle? descriptionStyle; - - //Value for default to use in form - final DefaultValues? defaultValues; - - //isJustForm to use for show totally form or one for one - //final bool isJustForm; - - //imageUrl to use for send services - final String imageUrl; - - //index to use for initial form - final int index; - - //function to use for get detailt of form - final Function onSubmit; - - //widget to use loading form - final Widget? loading; - - //description to use for style text title widget form - final TextStyle? descriptionStyleText; - - //description to use style text description widget form - final TextStyle? titleStyleText; - - const SimpleJsonForm({ - Key? key, - required this.jsonSchema, - required this.index, - required this.imageUrl, - required this.onSubmit, - this.defaultValues, - this.crossAxisAlignment = CrossAxisAlignment.start, - this.padding, - this.title, - this.description, - this.descriptionStyle, - this.titleStyle, - this.loading, - this.descriptionStyleText, - this.titleStyleText, - }) : super(key: key); - - @override - State createState() => _SimpleJsonFormState(); -} - -class _SimpleJsonFormState extends State { - int _indexForm = 0; - late DefaultValues defaultValues; - @override - void initState() { - _indexForm = _indexForm; - defaultValues = widget.defaultValues ?? DefaultValues(); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return SingleChildScrollView( - child: Container( - padding: widget.padding, - child: Column( - crossAxisAlignment: widget.crossAxisAlignment, - children: [ - if (widget.title != null) - Text( - widget.title!, - style: widget.titleStyle, - textAlign: TextAlign.center, - ), - if (widget.description != null) - Text( - widget.description!, - style: widget.descriptionStyle, - ), - - //show form if exist - ...List.generate( - widget.jsonSchema.form.length, - (i) { - return Visibility( - visible: i == _indexForm, - child: Form( - key: SimpleJsonFormKey - .keyMapping[widget.jsonSchema.form[i].key], - child: Column( - children: widget.jsonSchema.form[i].properties! - .map( - (entry) => SimpleJsonFormField( - properties: entry, - imageUrl: widget.imageUrl, - descriptionStyleText: widget.descriptionStyleText, - titleStyleText: widget.titleStyleText, - hintDropdownText: defaultValues.hintDropdownText, - ), - ) - .toList(), - ), - ), - ); - }, - ), - - const SizedBox(height: 10), - widget.jsonSchema.form.isNotEmpty - ? FormButton( - lengthForm: widget.jsonSchema.form.length, - indexForm: _indexForm, - nextText: defaultValues.nextButtonText, - previousText: defaultValues.previousButtonText, - submitText: defaultValues.submitButtonText, - onNext: () { - final next = _nextForm(_indexForm); - if (next) { - setState(() { - _indexForm = _indexForm + 1; - }); - } - }, - onPrevious: () { - setState(() { - _indexForm = _indexForm - 1; - }); - }, - onSubmit: () => widget.onSubmit(_completeForm(_indexForm)), - ) - : SizedBox.fromSize(), - const SizedBox(height: 20), - ], - ), - ), - ); - } - - _completeForm(int index) { - if (widget.jsonSchema.form.isEmpty) return widget.jsonSchema; - final formKey = - SimpleJsonFormKey.keyMapping[widget.jsonSchema.form[_indexForm].key]; - if (formKey?.currentState?.validate() ?? false) return widget.jsonSchema; - return null; - } - - bool _nextForm(int index) { - if (widget.jsonSchema.form.isEmpty) return false; - final formKey = - SimpleJsonFormKey.keyMapping[widget.jsonSchema.form[_indexForm].key]; - if (formKey?.currentState?.validate() ?? false) return true; - DialogForm.of(context: context).infoDialog( - title: defaultValues.validationTitle, - description: defaultValues.validationDescription, - ); - return false; - } -} +import 'package:flutter/material.dart'; +import 'package:simple_json_form/simple_json_form.dart'; +import 'package:simple_json_form/src/key/simple_json_form_key.dart'; +import 'package:simple_json_form/src/utils/dialog_form.dart'; +import 'package:simple_json_form/src/widgets/form_button.dart'; +import 'package:simple_json_form/src/widgets/simple_json_form_field.dart'; + +class SimpleJsonForm extends StatefulWidget { + //JSON Schema to use to generate the form. + final JsonSchema jsonSchema; + + //crossAxisAlignment to use general form + final CrossAxisAlignment crossAxisAlignment; + + //padding to use general form + final EdgeInsetsGeometry? padding; + + //Title general to use the form + final String? title; + + //title style to use title the form + final TextStyle? titleStyle; + + //Description general to use the form + final String? description; + + //Description style to use description form + final TextStyle? descriptionStyle; + + //Value for default to use in form + final DefaultValues? defaultValues; + + //isJustForm to use for show totally form or one for one + //final bool isJustForm; + + //imageUrl to use for send services + final String imageUrl; + + //index to use for initial form + final int index; + + //function to use for get detailt of form + final Function onSubmit; + + //widget to use loading form + final Widget? loading; + + //description to use for style text title widget form + final TextStyle? descriptionStyleText; + + //description to use style text description widget form + final TextStyle? titleStyleText; + + const SimpleJsonForm({ + Key? key, + required this.jsonSchema, + required this.index, + required this.imageUrl, + required this.onSubmit, + this.defaultValues, + this.crossAxisAlignment = CrossAxisAlignment.start, + this.padding, + this.title, + this.description, + this.descriptionStyle, + this.titleStyle, + this.loading, + this.descriptionStyleText, + this.titleStyleText, + }) : super(key: key); + + @override + State createState() => _SimpleJsonFormState(); +} + +class _SimpleJsonFormState extends State { + int _indexForm = 0; + late DefaultValues defaultValues; + @override + void initState() { + _indexForm = _indexForm; + defaultValues = widget.defaultValues ?? DefaultValues(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Container( + padding: widget.padding, + child: Column( + crossAxisAlignment: widget.crossAxisAlignment, + children: [ + if (widget.title != null) + Text( + widget.title!, + style: widget.titleStyle, + textAlign: TextAlign.center, + ), + if (widget.description != null) + Text( + widget.description!, + style: widget.descriptionStyle, + ), + + //show form if exist + ...List.generate( + widget.jsonSchema.form.length, + (i) { + return Visibility( + visible: i == _indexForm, + child: Form( + key: SimpleJsonFormKey.generateFormKeyMapping(), + child: Column( + children: widget.jsonSchema.form[i].properties! + .map( + (entry) => SimpleJsonFormField( + properties: entry, + imageUrl: widget.imageUrl, + descriptionStyleText: widget.descriptionStyleText, + titleStyleText: widget.titleStyleText, + hintDropdownText: defaultValues.hintDropdownText, + isRTL: defaultValues.isRTL, + ), + ) + .toList(), + ), + ), + ); + }, + ), + + const SizedBox(height: 10), + widget.jsonSchema.form.isNotEmpty + ? FormButton( + lengthForm: widget.jsonSchema.form.length, + indexForm: _indexForm, + nextText: defaultValues.nextButtonText, + previousText: defaultValues.previousButtonText, + submitText: defaultValues.submitButtonText, + onNext: () { + final next = _nextForm(_indexForm); + if (next) { + setState(() { + _indexForm = _indexForm + 1; + }); + } + }, + onPrevious: () { + setState(() { + _indexForm = _indexForm - 1; + }); + }, + onSubmit: () => widget.onSubmit(_completeForm(_indexForm)), + ) + : SizedBox.fromSize(), + const SizedBox(height: 20), + ], + ), + ), + ); + } + + _completeForm(int index) { + if (widget.jsonSchema.form.isEmpty) return widget.jsonSchema; + final formKey = SimpleJsonFormKey.generateFormKeyMapping(); + if (formKey?.currentState?.validate() ?? false) return widget.jsonSchema; + return null; + } + + bool _nextForm(int index) { + if (widget.jsonSchema.form.isEmpty) return false; + final formKey = SimpleJsonFormKey.generateFormKeyMapping(); + if (formKey?.currentState?.validate() ?? false) return true; + DialogForm.of(context: context).infoDialog( + title: defaultValues.validationTitle, + description: defaultValues.validationDescription, + ); + return false; + } +} diff --git a/lib/src/ui/simple_json_form_view_model.dart b/lib/src/ui/simple_json_form_view_model.dart index 753ef83..ca9786d 100644 --- a/lib/src/ui/simple_json_form_view_model.dart +++ b/lib/src/ui/simple_json_form_view_model.dart @@ -1,20 +1,20 @@ -import 'package:flutter/widgets.dart'; - -class SimpleJsonFromViewModel extends ChangeNotifier { - SimpleJsonFromViewModel(); - - int _indexForm = 0; - - int get indexForm => _indexForm; - - void init(int index) { - _indexForm = index; - } - - void _setIndexForm(int index) { - _indexForm = index; - notifyListeners(); - } - - void changeIndexForm(int index) => _setIndexForm(index); -} +import 'package:flutter/widgets.dart'; + +class SimpleJsonFromViewModel extends ChangeNotifier { + SimpleJsonFromViewModel(); + + int _indexForm = 0; + + int get indexForm => _indexForm; + + void init(int index) { + _indexForm = index; + } + + void _setIndexForm(int index) { + _indexForm = index; + notifyListeners(); + } + + void changeIndexForm(int index) => _setIndexForm(index); +} diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart index 2fde647..0880308 100644 --- a/lib/src/utils/constants.dart +++ b/lib/src/utils/constants.dart @@ -1,19 +1,19 @@ -import 'package:flutter/material.dart'; - -class Constants { - static Color orangeColor = const Color(0xffFF9C00); - static Color yellowColor = const Color(0xffFFCC01); - static Color purpleColor = const Color(0xff4C2882); - static Color greenColor = const Color(0xff3AC75E); - static Color blueColor = const Color(0xff0084FF); - static Color lightBlueColor = const Color(0xff00b7ee); - static Color grayColor = const Color(0xff979797); - static Color grayLightColor = const Color(0xffCAD1D6); - static Color blackColor = const Color(0xff242424); - static Color redColor = const Color(0xffFF0000); - static Color redAlternateColor = const Color(0xFFEE3B33); - static Color greenLightColor = const Color(0xFF68D58B); - static Color buttonColor = const Color(0xff00c4ff); - static Color grayButtonColor = const Color(0xfff2f2f2); - static Color shadowButtonColor = const Color(0xffD3D3D3); -} +import 'package:flutter/material.dart'; + +class Constants { + static Color orangeColor = const Color(0xffFF9C00); + static Color yellowColor = const Color(0xffFFCC01); + static Color purpleColor = const Color(0xff4C2882); + static Color greenColor = const Color(0xff3AC75E); + static Color blueColor = const Color(0xff0084FF); + static Color lightBlueColor = const Color(0xff00b7ee); + static Color grayColor = const Color(0xff979797); + static Color grayLightColor = const Color(0xffCAD1D6); + static Color blackColor = const Color(0xff242424); + static Color redColor = const Color(0xffFF0000); + static Color redAlternateColor = const Color(0xFFEE3B33); + static Color greenLightColor = const Color(0xFF68D58B); + static Color buttonColor = const Color(0xff00c4ff); + static Color grayButtonColor = const Color(0xfff2f2f2); + static Color shadowButtonColor = const Color(0xffD3D3D3); +} diff --git a/lib/src/utils/dialog_form.dart b/lib/src/utils/dialog_form.dart index 43bf5ee..f5542a5 100644 --- a/lib/src/utils/dialog_form.dart +++ b/lib/src/utils/dialog_form.dart @@ -1,91 +1,91 @@ -import 'package:flutter/material.dart'; -import 'package:simple_json_form/src/utils/responsive.dart'; -import 'package:simple_json_form/src/widgets/primary_button.dart'; -import 'package:simple_json_form/src/widgets/text_cfirst.dart'; - -class DialogForm { - DialogForm({ - required this.buildContext, - this.loading, - }); - final BuildContext buildContext; - final Widget? loading; - - static DialogForm of({ - required BuildContext context, - Widget? loading, - }) => - DialogForm( - buildContext: context, - loading: loading, - ); - - void infoDialog({ - required String title, - required String description, - bool withButton = false, - Function()? func, - String? labelButton, - }) { - showDialog( - context: buildContext, - builder: (ctx) { - return AlertDialog( - title: Icon( - Icons.info_outline, - color: Theme.of(ctx).primaryColor, - size: Responsive.of(buildContext).dp(4), - ), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextCFirst( - title, - fontWeight: FontWeight.bold, - fontSize: Responsive.of(buildContext).dp(2.2), - colorText: Theme.of(ctx).primaryColor, - ), - TextCFirst( - description, - ), - const SizedBox( - height: 20, - ), - withButton - ? PrimaryButton( - onPressed: func!, - text: labelButton ?? "Ok", - ) - : Container(), - ], - ), - ); - }); - } - - void loadingDialog({required String title}) { - showDialog( - barrierDismissible: false, - context: buildContext, - builder: (ctx) { - return AlertDialog( - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - loading ?? const CircularProgressIndicator(), - const SizedBox( - height: 20, - ), - Text( - title, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 20, - ), - ], - ), - ); - }); - } -} +import 'package:flutter/material.dart'; +import 'package:simple_json_form/src/utils/responsive.dart'; +import 'package:simple_json_form/src/widgets/primary_button.dart'; +import 'package:simple_json_form/src/widgets/text_cfirst.dart'; + +class DialogForm { + DialogForm({ + required this.buildContext, + this.loading, + }); + final BuildContext buildContext; + final Widget? loading; + + static DialogForm of({ + required BuildContext context, + Widget? loading, + }) => + DialogForm( + buildContext: context, + loading: loading, + ); + + void infoDialog({ + required String title, + required String description, + bool withButton = false, + Function()? func, + String? labelButton, + }) { + showDialog( + context: buildContext, + builder: (ctx) { + return AlertDialog( + title: Icon( + Icons.info_outline, + color: Theme.of(ctx).primaryColor, + size: Responsive.of(buildContext).dp(4), + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextCFirst( + title, + fontWeight: FontWeight.bold, + fontSize: Responsive.of(buildContext).dp(2.2), + colorText: Theme.of(ctx).primaryColor, + ), + TextCFirst( + description, + ), + const SizedBox( + height: 20, + ), + withButton + ? PrimaryButton( + onPressed: func!, + text: labelButton ?? "Ok", + ) + : Container(), + ], + ), + ); + }); + } + + void loadingDialog({required String title}) { + showDialog( + barrierDismissible: false, + context: buildContext, + builder: (ctx) { + return AlertDialog( + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + loading ?? const CircularProgressIndicator(), + const SizedBox( + height: 20, + ), + Text( + title, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox( + height: 20, + ), + ], + ), + ); + }); + } +} diff --git a/lib/src/utils/form.dart b/lib/src/utils/form.dart index 87a7e6a..9790e40 100644 --- a/lib/src/utils/form.dart +++ b/lib/src/utils/form.dart @@ -1,68 +1,68 @@ -import 'package:flutter/services.dart'; - -String? validateEmptyField(String? value, String error) { - if (value == null) return null; - return value.isEmpty ? error : null; -} - -String? validateEmailField(String? value, String error) { - if (value == null) return null; - if (value.isEmpty) return error; - final regExp = RegExp( - r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"); - if (!regExp.hasMatch(value)) return 'El formato ingresado es inválido.'; - return value.isEmpty ? error : null; -} - -String? validateEmptyFieldWithLength( - String? value, int min, int max, String error) { - if (value == null) return null; - return value.isEmpty - ? error - : (value.length >= min && value.length <= max) - ? null - : "La longitud requerida del campo debe tener mínimo $min caracteres y máximo $max caracteres"; -} - -class NumericalRangeFormatter extends TextInputFormatter { - final int min; - final int max; - - NumericalRangeFormatter({required this.min, required this.max}); - - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, - TextEditingValue newValue, - ) { - if (newValue.text == '') { - return newValue; - } else if (int.parse(newValue.text) < min) { - return const TextEditingValue().copyWith(text: min.toString()); - } else { - return int.parse(newValue.text) > max ? oldValue : newValue; - } - } -} - -class UpperCaseTextFormatter extends TextInputFormatter { - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, TextEditingValue newValue) { - return TextEditingValue( - text: newValue.text.toUpperCase(), - selection: newValue.selection, - ); - } -} - -class LowerCaseTextFormatter extends TextInputFormatter { - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, TextEditingValue newValue) { - return TextEditingValue( - text: newValue.text.toLowerCase(), - selection: newValue.selection, - ); - } -} +import 'package:flutter/services.dart'; + +String? validateEmptyField(String? value, String error) { + if (value == null) return null; + return value.isEmpty ? error : null; +} + +String? validateEmailField(String? value, String error) { + if (value == null) return null; + if (value.isEmpty) return error; + final regExp = RegExp( + r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"); + if (!regExp.hasMatch(value)) return 'El formato ingresado es inválido.'; + return value.isEmpty ? error : null; +} + +String? validateEmptyFieldWithLength( + String? value, int min, int max, String error) { + if (value == null) return null; + return value.isEmpty + ? error + : (value.length >= min && value.length <= max) + ? null + : "La longitud requerida del campo debe tener mínimo $min caracteres y máximo $max caracteres"; +} + +class NumericalRangeFormatter extends TextInputFormatter { + final int min; + final int max; + + NumericalRangeFormatter({required this.min, required this.max}); + + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, + TextEditingValue newValue, + ) { + if (newValue.text == '') { + return newValue; + } else if (int.parse(newValue.text) < min) { + return const TextEditingValue().copyWith(text: min.toString()); + } else { + return int.parse(newValue.text) > max ? oldValue : newValue; + } + } +} + +class UpperCaseTextFormatter extends TextInputFormatter { + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { + return TextEditingValue( + text: newValue.text.toUpperCase(), + selection: newValue.selection, + ); + } +} + +class LowerCaseTextFormatter extends TextInputFormatter { + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { + return TextEditingValue( + text: newValue.text.toLowerCase(), + selection: newValue.selection, + ); + } +} diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart index d400ba3..36bda23 100644 --- a/lib/src/utils/utils.dart +++ b/lib/src/utils/utils.dart @@ -1,9 +1,9 @@ -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; - -String formatTimeOfDay(TimeOfDay tod) { - final now = DateTime.now(); - final dt = DateTime(now.year, now.month, now.day, tod.hour, tod.minute); - final format = DateFormat.jm(); //"6:00 AM" - return format.format(dt); -} +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +String formatTimeOfDay(TimeOfDay tod) { + final now = DateTime.now(); + final dt = DateTime(now.year, now.month, now.day, tod.hour, tod.minute); + final format = DateFormat.jm(); //"6:00 AM" + return format.format(dt); +} diff --git a/lib/src/widgets/custom_dropdown_widget.dart b/lib/src/widgets/custom_dropdown_widget.dart index 89f3651..cc17b54 100644 --- a/lib/src/widgets/custom_dropdown_widget.dart +++ b/lib/src/widgets/custom_dropdown_widget.dart @@ -1,115 +1,115 @@ -import 'package:flutter/material.dart'; -import 'package:simple_json_form/src/utils/constants.dart'; -import 'package:simple_json_form/src/widgets/text_cfirst.dart'; - -class CustomDropdownWidget extends StatelessWidget { - const CustomDropdownWidget({ - Key? key, - required this.onChanged, - required this.title, - required this.width, - this.isRequired = true, - this.droplist, - this.dropVal, - this.onTap, - }) : super(key: key); - - final Function onChanged; - final String title; - final double width; - final bool isRequired; - final List? droplist; - final String? dropVal; - final Function()? onTap; - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Stack( - children: [ - SizedBox( - width: width, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: DropdownButtonFormField( - iconEnabledColor: Constants.lightBlueColor, - icon: const RotatedBox( - quarterTurns: 3, - child: Icon( - Icons.arrow_back_ios_rounded, - size: 20, - color: Colors.grey, - ), - ), - decoration: InputDecoration( - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Constants.lightBlueColor, width: 0.0), - ), - border: OutlineInputBorder( - borderSide: - BorderSide(color: Constants.lightBlueColor)), - ), - value: dropVal, - hint: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isRequired - ? const TextCFirst( - "* ", - fontWeight: FontWeight.bold, - colorText: Colors.red, - ) - : const SizedBox.shrink(), - TextCFirst( - title, - colorText: onTap != null - ? Constants.grayColor - : Constants.grayLightColor, - ), - ], - ), - isExpanded: true, - iconSize: 30.0, - // style: TextStyle( - // color: Colors.black, - // ), - items: droplist != null - ? droplist!.map( - (val) { - return DropdownMenuItem( - value: val, - child: Text(val), - ); - }, - ).toList() - : ['All', 'Two', 'Three'].map( - (val) { - return DropdownMenuItem( - value: val, - child: Text(val), - ); - }, - ).toList(), - onChanged: (val) { - onChanged(val); - }, - ), - ), - ), - onTap == null - ? const SizedBox.shrink() - : InkWell( - onTap: () => onTap!(), - child: SizedBox( - width: width, - height: 50, - ), - ) - ], - ), - ], - ); - } -} +import 'package:flutter/material.dart'; +import 'package:simple_json_form/src/utils/constants.dart'; +import 'package:simple_json_form/src/widgets/text_cfirst.dart'; + +class CustomDropdownWidget extends StatelessWidget { + const CustomDropdownWidget({ + Key? key, + required this.onChanged, + required this.title, + required this.width, + this.isRequired = true, + this.droplist, + this.dropVal, + this.onTap, + }) : super(key: key); + + final Function onChanged; + final String title; + final double width; + final bool isRequired; + final List? droplist; + final String? dropVal; + final Function()? onTap; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Stack( + children: [ + SizedBox( + width: width, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: DropdownButtonFormField( + iconEnabledColor: Constants.lightBlueColor, + icon: const RotatedBox( + quarterTurns: 3, + child: Icon( + Icons.arrow_back_ios_rounded, + size: 20, + color: Colors.grey, + ), + ), + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Constants.lightBlueColor, width: 0.0), + ), + border: OutlineInputBorder( + borderSide: + BorderSide(color: Constants.lightBlueColor)), + ), + value: dropVal, + hint: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + isRequired + ? const TextCFirst( + "* ", + fontWeight: FontWeight.bold, + colorText: Colors.red, + ) + : const SizedBox.shrink(), + TextCFirst( + title, + colorText: onTap != null + ? Constants.grayColor + : Constants.grayLightColor, + ), + ], + ), + isExpanded: true, + iconSize: 30.0, + // style: TextStyle( + // color: Colors.black, + // ), + items: droplist != null + ? droplist!.map( + (val) { + return DropdownMenuItem( + value: val, + child: Text(val), + ); + }, + ).toList() + : ['All', 'Two', 'Three'].map( + (val) { + return DropdownMenuItem( + value: val, + child: Text(val), + ); + }, + ).toList(), + onChanged: (val) { + onChanged(val); + }, + ), + ), + ), + onTap == null + ? const SizedBox.shrink() + : InkWell( + onTap: () => onTap!(), + child: SizedBox( + width: width, + height: 50, + ), + ) + ], + ), + ], + ); + } +} diff --git a/lib/src/widgets/form_button.dart b/lib/src/widgets/form_button.dart index eef8eed..2949b61 100644 --- a/lib/src/widgets/form_button.dart +++ b/lib/src/widgets/form_button.dart @@ -1,148 +1,151 @@ -import 'package:flutter/material.dart'; -import 'package:simple_json_form/src/utils/responsive.dart'; -import 'package:simple_json_form/src/widgets/primary_button.dart'; - -class FormButton extends StatelessWidget { - const FormButton({ - Key? key, - required this.lengthForm, - required this.indexForm, - required this.nextText, - required this.previousText, - required this.submitText, - this.onSubmit, - this.onNext, - this.onPrevious, - }) : super(key: key); - - final int lengthForm; - final int indexForm; - final String nextText; - final String previousText; - final String submitText; - final Function()? onSubmit; - final Function()? onNext; - final Function()? onPrevious; - - @override - Widget build(BuildContext context) { - return lengthForm == 1 - ? _OneButtonForm( - text: submitText, - onPressed: onSubmit, - ) - : _ManyButtonForm( - isFinish: lengthForm == indexForm + 1, - nextText: nextText, - previousText: previousText, - indexForm: indexForm, - submitText: submitText, - onNext: onNext, - onPrevious: onPrevious, - onSubmit: onSubmit, - ); - } -} - -class _OneButtonForm extends StatelessWidget { - const _OneButtonForm({ - Key? key, - required this.text, - this.onPressed, - }) : super(key: key); - final String text; - final Function()? onPressed; - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.symmetric( - horizontal: Responsive.of(context).dp(2), - ), - child: PrimaryButton( - onPressed: () { - if (onPressed != null) onPressed!(); - }, - text: text, - ), - ); - } -} - -class _ManyButtonForm extends StatelessWidget { - const _ManyButtonForm({ - Key? key, - required this.isFinish, - required this.nextText, - required this.previousText, - required this.submitText, - required this.indexForm, - this.onSubmit, - this.onNext, - this.onPrevious, - }) : super(key: key); - - final bool isFinish; - final int indexForm; - final String nextText; - final String previousText; - final String submitText; - final Function()? onSubmit; - final Function()? onNext; - final Function()? onPrevious; - - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.symmetric( - horizontal: Responsive.of(context).dp(2), - ), - child: isFinish - ? Column( - children: [ - PrimaryButton( - onPressed: () { - if (onPrevious != null) onPrevious!(); - }, - text: previousText, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 20), - PrimaryButton( - onPressed: () { - if (onSubmit != null) onSubmit!(); - }, - text: submitText, - overflow: TextOverflow.ellipsis, - ), - ], - ) - : indexForm == 0 - ? PrimaryButton( - onPressed: () { - if (onNext != null) onNext!(); - }, - text: nextText, - ) - : Column( - //mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - PrimaryButton( - onPressed: () { - if (onPrevious != null) onPrevious!(); - }, - text: previousText, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 20), - PrimaryButton( - onPressed: () { - if (onNext != null) onNext!(); - }, - text: nextText, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ); - } -} +import 'package:flutter/material.dart'; +import 'package:simple_json_form/src/utils/responsive.dart'; +import 'package:simple_json_form/src/widgets/primary_button.dart'; + +class FormButton extends StatelessWidget { + const FormButton({ + Key? key, + required this.lengthForm, + required this.indexForm, + required this.nextText, + required this.previousText, + required this.submitText, + this.onSubmit, + this.onNext, + this.onPrevious, + }) : super(key: key); + + final int lengthForm; + final int indexForm; + final String nextText; + final String previousText; + final String submitText; + final Function()? onSubmit; + final Function()? onNext; + final Function()? onPrevious; + + @override + Widget build(BuildContext context) { + return lengthForm == 1 + ? _OneButtonForm( + text: submitText, + onPressed: onSubmit, + ) + : _ManyButtonForm( + isFinish: lengthForm == indexForm + 1, + nextText: nextText, + previousText: previousText, + indexForm: indexForm, + submitText: submitText, + onNext: onNext, + onPrevious: onPrevious, + onSubmit: onSubmit, + ); + } +} + +class _OneButtonForm extends StatelessWidget { + const _OneButtonForm({ + Key? key, + required this.text, + this.onPressed, + }) : super(key: key); + final String text; + final Function()? onPressed; + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric( + horizontal: Responsive.of(context).dp(2), + ), + child: PrimaryButton( + onPressed: () { + if (onPressed != null) onPressed!(); + }, + text: text, + ), + ); + } +} + +class _ManyButtonForm extends StatelessWidget { + const _ManyButtonForm({ + Key? key, + required this.isFinish, + required this.nextText, + required this.previousText, + required this.submitText, + required this.indexForm, + this.onSubmit, + this.onNext, + this.onPrevious, + }) : super(key: key); + + final bool isFinish; + final int indexForm; + final String nextText; + final String previousText; + final String submitText; + final Function()? onSubmit; + final Function()? onNext; + final Function()? onPrevious; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric( + horizontal: Responsive.of(context).dp(2), + ), + child: isFinish + ? Column( + children: [ + PrimaryButton( + onPressed: () { + if (onPrevious != null) onPrevious!(); + }, + text: previousText, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 20), + PrimaryButton( + onPressed: () { + if (onSubmit != null) onSubmit!(); + }, + text: submitText, + overflow: TextOverflow.ellipsis, + textStyle: TextStyle( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, + )), + ], + ) + : indexForm == 0 + ? PrimaryButton( + onPressed: () { + if (onNext != null) onNext!(); + }, + text: nextText, + ) + : Column( + //mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + PrimaryButton( + onPressed: () { + if (onPrevious != null) onPrevious!(); + }, + text: previousText, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 20), + PrimaryButton( + onPressed: () { + if (onNext != null) onNext!(); + }, + text: nextText, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ); + } +} diff --git a/lib/src/widgets/input_label.dart b/lib/src/widgets/input_label.dart index 8470cb1..5353d33 100644 --- a/lib/src/widgets/input_label.dart +++ b/lib/src/widgets/input_label.dart @@ -1,29 +1,32 @@ -import 'package:flutter/material.dart'; - -class InputLabel extends StatelessWidget { - const InputLabel({ - Key? key, - required this.title, - required this.labelColor, - }) : super(key: key); - - final String? title; - final Color? labelColor; - - @override - Widget build(BuildContext context) { - return Visibility( - visible: title != null, - child: Container( - margin: const EdgeInsets.only(bottom: 10), - alignment: Alignment.centerLeft, - child: Text( - title ?? '', - style: TextStyle( - color: labelColor, - ), - ), - ), - ); - } -} +import 'package:flutter/material.dart'; + +class InputLabel extends StatelessWidget { + const InputLabel({ + Key? key, + required this.title, + required this.labelColor, + required this.isRTL, + }) : super(key: key); + + final String? title; + final Color? labelColor; + final bool isRTL; + + @override + Widget build(BuildContext context) { + return Visibility( + visible: title != null, + child: Container( + margin: const EdgeInsets.only(bottom: 10), + alignment: + isRTL == false ? Alignment.centerLeft : Alignment.centerRight, + child: Text( + title ?? '', + style: TextStyle( + color: labelColor, + ), + ), + ), + ); + } +} diff --git a/lib/src/widgets/input_text.dart b/lib/src/widgets/input_text.dart index d025593..828cda7 100644 --- a/lib/src/widgets/input_text.dart +++ b/lib/src/widgets/input_text.dart @@ -1,99 +1,106 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -import 'input_label.dart'; - -class InputText extends StatelessWidget { - const InputText({ - Key? key, - this.controller, - this.textCapitalization = TextCapitalization.none, - this.inputFormatters, - this.labelText = '', - this.prefixIcon, - this.validator, - this.keyboardType, - this.onChanged, - this.enabled = true, - this.readOnly = false, - this.margin = const EdgeInsets.symmetric(vertical: 12), - this.suffixIcon, - this.onTap, - this.textStyle, - this.title, - this.filled = false, - this.obscureText = false, - this.labelColor, - this.maxLines, - this.errorMaxLines, - }) : super(key: key); - - final TextEditingController? controller; - final List? inputFormatters; - final String? labelText; - final Widget? prefixIcon; - final String? Function(String?)? validator; - final TextInputType? keyboardType; - final void Function(String)? onChanged; - final bool enabled; - final bool readOnly; - final EdgeInsetsGeometry margin; - final Widget? suffixIcon; - final void Function()? onTap; - final TextStyle? textStyle; - final String? title; - final bool filled; - final bool obscureText; - final Color? labelColor; - final int? errorMaxLines; - final int? maxLines; - final TextCapitalization textCapitalization; - - @override - Widget build(BuildContext context) { - final disableFillColor = Colors.grey[200]; - - return Container( - margin: margin, - child: Column( - children: [ - InputLabel(title: title, labelColor: labelColor), - TextFormField( - textCapitalization: textCapitalization, - key: key, - readOnly: readOnly, - maxLines: maxLines, - controller: controller, - onChanged: onChanged, - onTap: onTap, - obscureText: obscureText, - inputFormatters: inputFormatters, - enabled: enabled, - style: textStyle, - decoration: InputDecoration( - errorMaxLines: errorMaxLines, - floatingLabelBehavior: FloatingLabelBehavior.never, - alignLabelWithHint: false, - labelStyle: TextStyle(color: Theme.of(context).hintColor), - hintStyle: TextStyle(color: Theme.of(context).hintColor), - labelText: labelText, - filled: filled, - fillColor: enabled ? const Color(0xffF1F2F5) : disableFillColor, - border: OutlineInputBorder( - borderSide: const BorderSide( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.circular(8)), - prefixIcon: prefixIcon, - suffixIcon: suffixIcon, - ), - validator: validator, - cursorColor: Theme.of(context).primaryColor, - keyboardType: keyboardType, - ), - ], - ), - ); - } -} +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'input_label.dart'; + +class InputText extends StatelessWidget { + const InputText({ + Key? key, + this.controller, + this.textCapitalization = TextCapitalization.none, + this.inputFormatters, + this.labelText = '', + this.prefixIcon, + this.validator, + this.keyboardType, + this.onChanged, + this.enabled = true, + this.readOnly = false, + this.margin = const EdgeInsets.symmetric(vertical: 12), + this.suffixIcon, + this.onTap, + this.textStyle, + this.title, + this.filled = false, + this.obscureText = false, + this.labelColor, + this.maxLines, + this.errorMaxLines, + required this.isRTL, + }) : super(key: key); + + final TextEditingController? controller; + final List? inputFormatters; + final String? labelText; + final Widget? prefixIcon; + final String? Function(String?)? validator; + final TextInputType? keyboardType; + final void Function(String)? onChanged; + final bool enabled; + final bool readOnly; + final EdgeInsetsGeometry margin; + final Widget? suffixIcon; + final void Function()? onTap; + final TextStyle? textStyle; + final String? title; + final bool filled; + final bool obscureText; + final Color? labelColor; + final int? errorMaxLines; + final int? maxLines; + final TextCapitalization textCapitalization; + final bool isRTL; + + @override + Widget build(BuildContext context) { + final disableFillColor = Colors.grey[200]; + + return Container( + margin: margin, + child: Column( + children: [ + InputLabel( + title: title, + labelColor: labelColor, + isRTL: isRTL, + ), + TextFormField( + textCapitalization: textCapitalization, + key: key, + readOnly: readOnly, + maxLines: maxLines, + controller: controller, + onChanged: onChanged, + onTap: onTap, + obscureText: obscureText, + inputFormatters: inputFormatters, + enabled: enabled, + style: textStyle, + decoration: InputDecoration( + errorMaxLines: errorMaxLines, + floatingLabelBehavior: FloatingLabelBehavior.never, + alignLabelWithHint: false, + labelStyle: TextStyle(color: Theme.of(context).hintColor), + hintStyle: TextStyle(color: Theme.of(context).hintColor), + labelText: labelText, + filled: filled, + fillColor: enabled ? const Color(0xffF1F2F5) : disableFillColor, + border: OutlineInputBorder( + borderSide: const BorderSide( + color: Colors.grey, + width: 1.0, + ), + borderRadius: BorderRadius.circular(8)), + prefixIcon: prefixIcon, + suffixIcon: suffixIcon, + ), + validator: validator, + cursorColor: Theme.of(context).primaryColor, + keyboardType: keyboardType, + textInputAction: TextInputAction.done, + ), + ], + ), + ); + } +} diff --git a/lib/src/widgets/primary_button.dart b/lib/src/widgets/primary_button.dart index 8647de1..c2a15b7 100644 --- a/lib/src/widgets/primary_button.dart +++ b/lib/src/widgets/primary_button.dart @@ -1,51 +1,56 @@ -import 'package:flutter/material.dart'; - -class PrimaryButton extends StatelessWidget { - const PrimaryButton({ - Key? key, - required this.onPressed, - required this.text, - this.alignment, - this.height = 50, - this.width = double.infinity, - this.radius = 10, - this.textStyle, - this.buttonColor, - this.elevation, - this.overflow, - }) : super(key: key); - - final void Function() onPressed; - final String text; - final TextStyle? textStyle; - final AlignmentGeometry? alignment; - final double height; - final double width; - final double radius; - final Color? buttonColor; - final double? elevation; - final TextOverflow? overflow; - - @override - Widget build(BuildContext context) { - return ElevatedButton( - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 40), - primary: buttonColor ?? Theme.of(context).primaryColor, - minimumSize: Size(width, height), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(radius), - ), - alignment: alignment, - elevation: elevation, - ), - onPressed: onPressed, - child: Text( - text, - style: const TextStyle(fontWeight: FontWeight.w700).merge(textStyle), - textAlign: TextAlign.center, - overflow: overflow, - ), - ); - } -} +import 'package:flutter/material.dart'; + +class PrimaryButton extends StatelessWidget { + const PrimaryButton({ + Key? key, + required this.onPressed, + required this.text, + this.alignment, + this.height = 50, + this.width = double.infinity, + this.radius = 10, + this.textStyle, + this.buttonColor, + this.elevation, + this.overflow, + }) : super(key: key); + + final void Function() onPressed; + final String text; + final TextStyle? textStyle; + final AlignmentGeometry? alignment; + final double height; + final double width; + final double radius; + final Color? buttonColor; + final double? elevation; + final TextOverflow? overflow; + + @override + Widget build(BuildContext context) { + return ElevatedButton( + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 40), + primary: buttonColor ?? Theme.of(context).primaryColor, + backgroundColor: Colors.white, + minimumSize: Size(width, height), + side: BorderSide(color: Theme.of(context).primaryColor), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30.0), + ), + alignment: alignment, + elevation: elevation, + ), + onPressed: onPressed, + child: Text( + text, + style: const TextStyle( + color: Colors.black, + fontWeight: FontWeight.normal, + ).merge(textStyle), + textAlign: TextAlign.center, + overflow: overflow, + ), + ); + } +} diff --git a/lib/src/widgets/secondary_button.dart b/lib/src/widgets/secondary_button.dart index 4e63890..6b91024 100644 --- a/lib/src/widgets/secondary_button.dart +++ b/lib/src/widgets/secondary_button.dart @@ -1,50 +1,50 @@ -import 'package:flutter/material.dart'; - -class SecondaryButton extends StatelessWidget { - const SecondaryButton({ - Key? key, - required this.onPressed, - required this.text, - required this.iconWidget, - this.textAlign, - this.alignment, - this.height = 50, - this.width = double.infinity, - this.radius = 10, - this.textStyle, - this.buttonColor, - }) : super(key: key); - - final void Function() onPressed; - final String text; - final TextStyle? textStyle; - final AlignmentGeometry? alignment; - final double height; - final double width; - final double radius; - final Color? buttonColor; - final Widget iconWidget; - final TextAlign? textAlign; - - @override - Widget build(BuildContext context) { - return ElevatedButton.icon( - icon: iconWidget, - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 40), - primary: buttonColor ?? Theme.of(context).primaryColor, - minimumSize: Size(width, height), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(radius), - ), - alignment: alignment, - ), - onPressed: onPressed, - label: Text( - text, - textAlign: textAlign, - style: const TextStyle(fontWeight: FontWeight.w700).merge(textStyle), - ), - ); - } -} +import 'package:flutter/material.dart'; + +class SecondaryButton extends StatelessWidget { + const SecondaryButton({ + Key? key, + required this.onPressed, + required this.text, + required this.iconWidget, + this.textAlign, + this.alignment, + this.height = 50, + this.width = double.infinity, + this.radius = 10, + this.textStyle, + this.buttonColor, + }) : super(key: key); + + final void Function() onPressed; + final String text; + final TextStyle? textStyle; + final AlignmentGeometry? alignment; + final double height; + final double width; + final double radius; + final Color? buttonColor; + final Widget iconWidget; + final TextAlign? textAlign; + + @override + Widget build(BuildContext context) { + return ElevatedButton.icon( + icon: iconWidget, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 40), + primary: buttonColor ?? Theme.of(context).primaryColor, + minimumSize: Size(width, height), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(radius), + ), + alignment: alignment, + ), + onPressed: onPressed, + label: Text( + text, + textAlign: textAlign, + style: const TextStyle(fontWeight: FontWeight.w700).merge(textStyle), + ), + ); + } +} diff --git a/lib/src/widgets/simple_json_form_field.dart b/lib/src/widgets/simple_json_form_field.dart index edca046..667221b 100644 --- a/lib/src/widgets/simple_json_form_field.dart +++ b/lib/src/widgets/simple_json_form_field.dart @@ -1,504 +1,515 @@ -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:simple_json_form/simple_json_form.dart'; -import 'package:simple_json_form/src/controller/simple_json_form_controller.dart'; -import 'package:simple_json_form/src/utils/constants.dart'; -import 'package:simple_json_form/src/utils/form.dart'; -import 'package:simple_json_form/src/utils/responsive.dart'; -import 'package:simple_json_form/src/utils/utils.dart'; -import 'package:simple_json_form/src/widgets/input_text.dart'; - -class SimpleJsonFormField extends StatefulWidget { - const SimpleJsonFormField({ - Key? key, - required this.properties, - required this.imageUrl, - required this.hintDropdownText, - this.descriptionStyleText, - this.titleStyleText, - }) : super(key: key); - - final Properties properties; - final String imageUrl; - final TextStyle? descriptionStyleText; - final TextStyle? titleStyleText; - final String hintDropdownText; - - @override - State createState() => _SimpleJsonFormFieldState(); -} - -class _SimpleJsonFormFieldState extends State { - @override - Widget build(BuildContext context) { - switch (widget.properties.type) { - case JsonSchemaType.multiple: - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16.0, top: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: Text( - widget.properties.title, - style: widget.titleStyleText, - ), - ), - if (widget.properties.description != null) - Text( - widget.properties.description!, - style: widget.descriptionStyleText, - ), - ], - ), - ), - ...widget.properties.fields!.map( - (entry) => RadioListTile( - value: entry, - groupValue: widget.properties.answer, - title: Text( - entry, - style: TextStyle( - fontWeight: FontWeight.normal, - fontSize: Responsive.of(context).dp(1.8), - ), - ), - onChanged: (value) { - widget.properties.answer = value; - setState(() {}); - }, - ), - ), - // widget.properties.remark - // ? SimpleJsonFormRemark( - // properties: widget.properties, - // ) - // : const SizedBox.shrink(), - ], - ); - case JsonSchemaType.dropdown: - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16.0, top: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: Text( - widget.properties.title, - style: widget.titleStyleText, - ), - ), - if (widget.properties.description != null) - Text( - widget.properties.description!, - style: widget.descriptionStyleText, - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16, - ), - child: DropdownButtonFormField( - iconEnabledColor: Constants.lightBlueColor, - decoration: InputDecoration( - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Constants.lightBlueColor, width: 0.0), - ), - border: - OutlineInputBorder(borderSide: BorderSide(color: Constants.lightBlueColor)), - ), - hint: Text(widget.hintDropdownText), - items: widget.properties.fields!.map( - (val) { - return DropdownMenuItem( - value: val, - child: Text(val), - ); - }, - ).toList(), - onChanged: (value) { - setState(() { - widget.properties.answer = value; - }); - }, - ), - ), - // widget.properties.remark - // ? SimpleJsonFormRemark( - // properties: widget.properties, - // ) - // : const SizedBox.shrink(), - ], - ); - - case JsonSchemaType.checkbox: - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16.0, top: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: Text( - widget.properties.title, - style: widget.titleStyleText, - ), - ), - if (widget.properties.description != null) - Text( - widget.properties.description!, - style: widget.descriptionStyleText, - ), - ], - ), - ), - ...widget.properties.fields!.map( - (entry) => CheckboxListTile( - controlAffinity: ListTileControlAffinity.leading, - dense: true, - title: Text( - entry, - style: TextStyle( - color: - widget.properties.answer[widget.properties.fields!.indexOf(entry)] != true - ? Colors.grey - : Colors.black, - fontWeight: FontWeight.normal, - fontSize: Responsive.of(context).dp(1.8), - ), - ), - value: widget.properties.answer[widget.properties.fields!.indexOf(entry)], - onChanged: (value) { - widget.properties.answer[widget.properties.fields!.indexOf(entry)] = value; - setState(() {}); - }, - ), - ), - // widget.properties.remark - // ? SimpleJsonFormRemark( - // properties: widget.properties, - // ) - // : const SizedBox.shrink(), - ], - ); - - case JsonSchemaType.time: - final controller = SimpleJsonFormController.getKeyController(widget.properties.key); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16, - ), - child: InputText( - controller: controller, - readOnly: true, - onTap: () => selectTime(context, controller), - validator: widget.properties.isRequired - ? (value) => validateEmptyFieldWithLength( - value, - widget.properties.validations?.length.min ?? 1, - widget.properties.validations?.length.max ?? 100, - widget.properties.validations?.message ?? 'Field is required', - ) - : null, - labelText: widget.properties.description, - maxLines: widget.properties.maxLine, - onChanged: (value) { - widget.properties.answer = value; - }, - title: widget.properties.title, - ), - ), - // widget.properties.remark - // ? SimpleJsonFormRemark( - // properties: widget.properties, - // ) - // : const SizedBox.shrink(), - ], - ); - - case JsonSchemaType.date: - final controller = SimpleJsonFormController.getKeyController(widget.properties.key); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16, - ), - child: InputText( - controller: controller, - readOnly: true, - onTap: () => selectDate(context, controller), - validator: widget.properties.isRequired - ? (value) => validateEmptyFieldWithLength( - value, - widget.properties.validations?.length.min ?? 1, - widget.properties.validations?.length.max ?? 100, - widget.properties.validations?.message ?? 'Field is required', - ) - : null, - labelText: widget.properties.description, - maxLines: widget.properties.maxLine, - onChanged: (value) { - widget.properties.answer = value; - }, - title: widget.properties.title, - ), - ), - // widget.properties.remark - // ? SimpleJsonFormRemark( - // properties: widget.properties, - // ) - // : const SizedBox.shrink(), - ], - ); - - case JsonSchemaType.file: - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16.0, top: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: Text( - widget.properties.title, - style: widget.titleStyleText, - ), - ), - if (widget.properties.description != null) - Text( - widget.properties.description!, - style: widget.descriptionStyleText, - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Stack( - alignment: Alignment.topRight, - children: [ - SizedBox( - height: 70, - width: 100, - child: Icon( - Icons.add_a_photo_outlined, - color: Colors.grey[500], - size: 70, - ), - ), - widget.properties.answer != null - ? const CircleAvatar( - backgroundColor: Colors.green, - radius: 15, - child: Icon( - Icons.check, - color: Colors.white, - ), - ) - : const SizedBox.shrink(), - ], - ), - ), - InkWell( - onTap: () async { - String url = widget.imageUrl; - setState(() { - widget.properties.answer = url; - }); - }, - child: const Padding( - padding: EdgeInsets.only(left: 5.0), - child: Text( - "Upload", - style: TextStyle( - color: Colors.black, - decoration: TextDecoration.underline, - ), - ), - ), - ), - ], - ), - ), - // widget.properties.remark - // ? SimpleJsonFormRemark( - // properties: widget.properties, - // ) - // : const SizedBox.shrink(), - ], - ); - - case JsonSchemaType.number: - final controller = SimpleJsonFormController.getKeyController(widget.properties.key); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16, - ), - child: InputText( - controller: controller, - keyboardType: TextInputType.number, - validator: widget.properties.isRequired - ? (value) => validateEmptyFieldWithLength( - value, - widget.properties.validations?.length.min ?? 1, - widget.properties.validations?.length.max ?? 100, - widget.properties.validations?.message ?? 'Field is required', - ) - : null, - labelText: widget.properties.description, - title: widget.properties.title, - readOnly: widget.properties.readOnly, - maxLines: widget.properties.maxLine, - onChanged: (value) { - //setState(() { - widget.properties.answer = value; - //}); - }, - ), - ), - // widget.properties.remark - // ? SimpleJsonFormRemark( - // properties: widget.properties, - // ) - // : const SizedBox.shrink(), - ], - ); - - case JsonSchemaType.text: - final controller = SimpleJsonFormController.getKeyController(widget.properties.key); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16, - ), - child: InputText( - controller: controller, - validator: widget.properties.isRequired - ? (value) => validateEmptyFieldWithLength( - value, - widget.properties.validations?.length.min ?? 1, - widget.properties.validations?.length.max ?? 100, - widget.properties.validations?.message ?? 'Field is required', - ) - : null, - labelText: widget.properties.description, - title: widget.properties.title, - maxLines: widget.properties.maxLine, - readOnly: widget.properties.readOnly, - onChanged: (value) { - //setState(() { - widget.properties.answer = value; - //}); - }, - ), - ), - // widget.properties.remark - // ? SimpleJsonFormRemark( - // properties: widget.properties, - // ) - // : const SizedBox.shrink(), - ], - ); - case JsonSchemaType.format1: - final raw = widget.properties.raw; - if (raw == null) return const SizedBox.shrink(); - List widgetFormat1 = []; - int index = 1; - for (var entry in raw) { - List widgetTemp = []; - for (Properties property in entry.properties) { - widgetTemp.add(SimpleJsonFormField( - properties: property, - imageUrl: widget.imageUrl, - descriptionStyleText: widget.descriptionStyleText, - titleStyleText: widget.titleStyleText, - hintDropdownText: widget.hintDropdownText, - )); - } - widgetFormat1.add( - ExpansionTile( - title: Text( - entry.title, - style: widget.titleStyleText, - ), - subtitle: Text( - entry.description ?? '', - style: widget.descriptionStyleText, - ), - controlAffinity: ListTileControlAffinity.leading, - children: [...widgetTemp], - ), - ); - } - - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: Column( - children: [...widgetFormat1], - ), - ); - - default: - return Container(); - } - } - - selectDate(BuildContext context, TextEditingController? controller) async { - final DateTime? picked = await showDatePicker( - context: context, - initialDate: DateTime.now(), // Refer step 1 - firstDate: DateTime.now(), - lastDate: DateTime.now().add(const Duration(hours: 43800)), - ); - - if (picked == null) return; - controller?.text = DateFormat('dd-MM-yyyy').format(picked); - widget.properties.answer = picked; - } - - selectTime(BuildContext context, TextEditingController? controller) async { - final TimeOfDay? picked = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (picked == null) return; - final formatTime = formatTimeOfDay(picked); - controller?.text = formatTime; - widget.properties.answer = picked; - } -} +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:simple_json_form/simple_json_form.dart'; +import 'package:simple_json_form/src/controller/simple_json_form_controller.dart'; +import 'package:simple_json_form/src/utils/constants.dart'; +import 'package:simple_json_form/src/utils/form.dart'; +import 'package:simple_json_form/src/utils/responsive.dart'; +import 'package:simple_json_form/src/utils/utils.dart'; +import 'package:simple_json_form/src/widgets/input_text.dart'; + +class SimpleJsonFormField extends StatefulWidget { + const SimpleJsonFormField({ + Key? key, + required this.properties, + required this.imageUrl, + required this.hintDropdownText, + required this.isRTL, + this.descriptionStyleText, + this.titleStyleText, + }) : super(key: key); + + final Properties properties; + final String imageUrl; + final TextStyle? descriptionStyleText; + final TextStyle? titleStyleText; + final String hintDropdownText; + final bool isRTL; + + @override + State createState() => _SimpleJsonFormFieldState(); +} + +class _SimpleJsonFormFieldState extends State { + @override + void initState() { + // TODO: implement initState + super.initState(); + } + +// used here to be static or render one time + TextEditingController controller = TextEditingController(); + + @override + Widget build(BuildContext context) { + switch (widget.properties.type) { + case JsonSchemaType.multiple: + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16.0, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: Text( + widget.properties.title, + style: widget.titleStyleText, + ), + ), + if (widget.properties.description != null) + Text( + widget.properties.description!, + style: widget.descriptionStyleText, + ), + ], + ), + ), + ...widget.properties.fields!.map( + (entry) => RadioListTile( + value: entry, + groupValue: widget.properties.answer, + title: Text( + entry, + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: Responsive.of(context).dp(1.8), + ), + ), + onChanged: (value) { + widget.properties.answer = value; + setState(() {}); + }, + ), + ), + // widget.properties.remark + // ? SimpleJsonFormRemark( + // properties: widget.properties, + // ) + // : const SizedBox.shrink(), + ], + ); + case JsonSchemaType.dropdown: + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16.0, right: 20.0, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: Text( + widget.properties.title, + style: widget.titleStyleText, + ), + ), + if (widget.properties.description != null) + Text( + widget.properties.description!, + style: widget.descriptionStyleText, + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 20.0, + ), + child: DropdownButtonFormField( + iconEnabledColor: Constants.purpleColor, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: + BorderSide(color: Constants.purpleColor, width: 0.0), + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: Constants.purpleColor)), + ), + hint: Text(widget.hintDropdownText), + items: widget.properties.fields!.map( + (val) { + return DropdownMenuItem( + value: val, + child: Text(val), + ); + }, + ).toList(), + onChanged: (value) { + setState(() { + widget.properties.answer = value; + }); + }, + ), + ), + // widget.properties.remark + // ? SimpleJsonFormRemark( + // properties: widget.properties, + // ) + // : const SizedBox.shrink(), + ], + ); + + case JsonSchemaType.checkbox: + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16.0, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: Text( + widget.properties.title, + style: widget.titleStyleText, + ), + ), + if (widget.properties.description != null) + Text( + widget.properties.description!, + style: widget.descriptionStyleText, + ), + ], + ), + ), + ...widget.properties.fields!.map( + (entry) => CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + dense: true, + title: Text( + entry, + style: TextStyle( + color: widget.properties.answer[ + widget.properties.fields!.indexOf(entry)] != + true + ? Colors.grey + : Colors.black, + fontWeight: FontWeight.normal, + fontSize: Responsive.of(context).dp(1.8), + ), + ), + value: widget.properties + .answer[widget.properties.fields!.indexOf(entry)], + onChanged: (value) { + widget.properties + .answer[widget.properties.fields!.indexOf(entry)] = value; + setState(() {}); + }, + ), + ), + // widget.properties.remark + // ? SimpleJsonFormRemark( + // properties: widget.properties, + // ) + // : const SizedBox.shrink(), + ], + ); + + case JsonSchemaType.time: + final controller = + SimpleJsonFormController.getKeyController(widget.properties.key); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16, + ), + child: InputText( + isRTL: widget.isRTL, + controller: controller, + readOnly: true, + onTap: () => selectTime(context, controller), + validator: widget.properties.isRequired + ? (value) => validateEmptyFieldWithLength( + value, + widget.properties.validations?.length.min ?? 1, + widget.properties.validations?.length.max ?? 100, + widget.properties.validations?.message ?? + 'Field is required', + ) + : null, + labelText: widget.properties.description, + maxLines: widget.properties.maxLine, + onChanged: (value) { + widget.properties.answer = value; + }, + title: widget.properties.title, + ), + ), + ], + ); + + case JsonSchemaType.date: + final controller = + SimpleJsonFormController.getKeyController(widget.properties.key); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16, + ), + child: InputText( + isRTL: widget.isRTL, + controller: controller, + readOnly: true, + onTap: () => selectDate(context, controller), + validator: widget.properties.isRequired + ? (value) => validateEmptyFieldWithLength( + value, + widget.properties.validations?.length.min ?? 1, + widget.properties.validations?.length.max ?? 100, + widget.properties.validations?.message ?? + 'Field is required', + ) + : null, + labelText: widget.properties.description, + maxLines: widget.properties.maxLine, + onChanged: (value) { + widget.properties.answer = value; + }, + title: widget.properties.title, + ), + ), + ], + ); + + case JsonSchemaType.file: + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16.0, top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: Text( + widget.properties.title, + style: widget.titleStyleText, + ), + ), + if (widget.properties.description != null) + Text( + widget.properties.description!, + style: widget.descriptionStyleText, + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Stack( + alignment: Alignment.topRight, + children: [ + SizedBox( + height: 70, + width: 100, + child: Icon( + Icons.add_a_photo_outlined, + color: Colors.grey[500], + size: 70, + ), + ), + widget.properties.answer != null + ? const CircleAvatar( + backgroundColor: Colors.green, + radius: 15, + child: Icon( + Icons.check, + color: Colors.white, + ), + ) + : const SizedBox.shrink(), + ], + ), + ), + InkWell( + onTap: () async { + String url = widget.imageUrl; + setState(() { + widget.properties.answer = url; + }); + }, + child: const Padding( + padding: EdgeInsets.only(left: 5.0), + child: Text( + "Upload", + style: TextStyle( + color: Colors.black, + decoration: TextDecoration.underline, + ), + ), + ), + ), + ], + ), + ), + ], + ); + + case JsonSchemaType.number: + final controller = + SimpleJsonFormController.getKeyController(widget.properties.key); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16, + ), + child: InputText( + isRTL: widget.isRTL, + controller: controller, + keyboardType: TextInputType.number, + validator: widget.properties.isRequired + ? (value) => validateEmptyFieldWithLength( + value, + widget.properties.validations?.length.min ?? 1, + widget.properties.validations?.length.max ?? 100, + widget.properties.validations?.message ?? + 'Field is required', + ) + : null, + labelText: widget.properties.description, + title: widget.properties.title, + readOnly: widget.properties.readOnly, + maxLines: widget.properties.maxLine, + onChanged: (value) { + //setState(() { + widget.properties.answer = value; + //}); + }, + ), + ), + // widget.properties.remark + // ? SimpleJsonFormRemark( + // properties: widget.properties, + // ) + // : const SizedBox.shrink(), + ], + ); + + case JsonSchemaType.text: + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16, + ), + child: InputText( + isRTL: widget.isRTL, + controller: controller, + validator: widget.properties.isRequired + ? (value) => validateEmptyFieldWithLength( + value, + widget.properties.validations?.length.min ?? 1, + widget.properties.validations?.length.max ?? 100, + widget.properties.validations?.message ?? + 'Field is required', + ) + : null, + labelText: widget.properties.description, + title: widget.properties.title, + maxLines: widget.properties.maxLine, + readOnly: widget.properties.readOnly, + onChanged: (value) { + //setState(() { + widget.properties.answer = value; + //}); + }, + ), + ), + // widget.properties.remark + // ? SimpleJsonFormRemark( + // properties: widget.properties, + // ) + // : const SizedBox.shrink(), + ], + ); + case JsonSchemaType.format1: + final raw = widget.properties.raw; + if (raw == null) return const SizedBox.shrink(); + List widgetFormat1 = []; + int index = 1; + for (var entry in raw) { + List widgetTemp = []; + for (Properties property in entry.properties) { + widgetTemp.add(SimpleJsonFormField( + properties: property, + imageUrl: widget.imageUrl, + descriptionStyleText: widget.descriptionStyleText, + titleStyleText: widget.titleStyleText, + hintDropdownText: widget.hintDropdownText, + isRTL: widget.isRTL, + )); + } + widgetFormat1.add( + ExpansionTile( + title: Text( + entry.title, + style: widget.titleStyleText, + ), + subtitle: Text( + entry.description ?? '', + style: widget.descriptionStyleText, + ), + controlAffinity: ListTileControlAffinity.leading, + children: [...widgetTemp], + ), + ); + } + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Column( + children: [...widgetFormat1], + ), + ); + + default: + return Container(); + } + } + + selectDate(BuildContext context, TextEditingController? controller) async { + final DateTime? picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), // Refer step 1 + firstDate: DateTime.now(), + lastDate: DateTime.now().add(const Duration(hours: 43800)), + ); + + if (picked == null) return; + controller?.text = DateFormat('dd-MM-yyyy').format(picked); + widget.properties.answer = picked; + } + + selectTime(BuildContext context, TextEditingController? controller) async { + final TimeOfDay? picked = await showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ); + if (picked == null) return; + final formatTime = formatTimeOfDay(picked); + controller?.text = formatTime; + widget.properties.answer = picked; + } +} diff --git a/lib/src/widgets/simple_json_form_remark.dart b/lib/src/widgets/simple_json_form_remark.dart index 0ce73e4..7012dc3 100644 --- a/lib/src/widgets/simple_json_form_remark.dart +++ b/lib/src/widgets/simple_json_form_remark.dart @@ -1,33 +1,33 @@ -// import 'package:flutter/material.dart'; -// import 'package:simple_json_form/simple_json_form.dart'; -// import 'package:simple_json_form/src/controller/simple_json_form_controller.dart'; -// import 'package:simple_json_form/src/widgets/input_text.dart'; - -// class SimpleJsonFormRemark extends StatelessWidget { -// const SimpleJsonFormRemark({ -// Key? key, -// required this.properties, -// }) : super(key: key); -// final Properties properties; - -// @override -// Widget build(BuildContext context) { -// final controller = -// SimpleJsonFormController.getKeyController('${properties.key}_remark'); -// return Padding( -// padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 8), -// child: Column( -// children: [ -// InputText( -// controller: controller, -// title: properties.remarkTitle ?? 'Enter remarks', -// labelText: properties.remarkLabel ?? 'Enter the remark', -// onChanged: (value) { -// properties.remarkData = value; -// }, -// ), -// ], -// ), -// ); -// } -// } +// import 'package:flutter/material.dart'; +// import 'package:simple_json_form/simple_json_form.dart'; +// import 'package:simple_json_form/src/controller/simple_json_form_controller.dart'; +// import 'package:simple_json_form/src/widgets/input_text.dart'; + +// class SimpleJsonFormRemark extends StatelessWidget { +// const SimpleJsonFormRemark({ +// Key? key, +// required this.properties, +// }) : super(key: key); +// final Properties properties; + +// @override +// Widget build(BuildContext context) { +// final controller = +// SimpleJsonFormController.getKeyController('${properties.key}_remark'); +// return Padding( +// padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 8), +// child: Column( +// children: [ +// InputText( +// controller: controller, +// title: properties.remarkTitle ?? 'Enter remarks', +// labelText: properties.remarkLabel ?? 'Enter the remark', +// onChanged: (value) { +// properties.remarkData = value; +// }, +// ), +// ], +// ), +// ); +// } +// } diff --git a/lib/src/widgets/text_cfirst.dart b/lib/src/widgets/text_cfirst.dart index ea863fc..1d6ea79 100644 --- a/lib/src/widgets/text_cfirst.dart +++ b/lib/src/widgets/text_cfirst.dart @@ -1,30 +1,30 @@ -import 'package:flutter/material.dart'; - -class TextCFirst extends StatelessWidget { - const TextCFirst(this.text, - {Key? key, - this.fontSize = 12, - this.fontWeight = FontWeight.normal, - this.fontFamily, - this.colorText = const Color(0xff242424)}) - : super(key: key); - - final String text; - final double fontSize; - final FontWeight fontWeight; - final Color colorText; - final String? fontFamily; - - @override - Widget build(BuildContext context) { - return Text( - text, - style: TextStyle( - color: colorText, - fontSize: fontSize, - fontWeight: fontWeight, - fontFamily: fontFamily, - ), - ); - } -} +import 'package:flutter/material.dart'; + +class TextCFirst extends StatelessWidget { + const TextCFirst(this.text, + {Key? key, + this.fontSize = 12, + this.fontWeight = FontWeight.normal, + this.fontFamily, + this.colorText = const Color(0xff242424)}) + : super(key: key); + + final String text; + final double fontSize; + final FontWeight fontWeight; + final Color colorText; + final String? fontFamily; + + @override + Widget build(BuildContext context) { + return Text( + text, + style: TextStyle( + color: colorText, + fontSize: fontSize, + fontWeight: fontWeight, + fontFamily: fontFamily, + ), + ); + } +} diff --git a/lib/src/widgets/title_text.dart b/lib/src/widgets/title_text.dart index 809c930..ad6c55c 100644 --- a/lib/src/widgets/title_text.dart +++ b/lib/src/widgets/title_text.dart @@ -1,26 +1,26 @@ -import 'package:flutter/material.dart'; - -class TitleText extends StatelessWidget { - const TitleText({ - Key? key, - required this.title, - this.fontSize = 32, - }) : super(key: key); - - final String title; - final double fontSize; - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 28), - child: Text( - title, - style: TextStyle( - fontSize: fontSize, - fontWeight: FontWeight.w800, - letterSpacing: 0.36, - ), - ), - ); - } -} +import 'package:flutter/material.dart'; + +class TitleText extends StatelessWidget { + const TitleText({ + Key? key, + required this.title, + this.fontSize = 32, + }) : super(key: key); + + final String title; + final double fontSize; + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 28), + child: Text( + title, + style: TextStyle( + fontSize: fontSize, + fontWeight: FontWeight.w800, + letterSpacing: 0.36, + ), + ), + ); + } +}