Files
flutter_wisetronic/lib/widgets/general/attribute/qty_options.dart
2023-12-15 21:34:23 +08:00

442 lines
18 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import '../../../events/eventbus.dart';
import '../../../events/events.dart';
import '../../../generated/l10n.dart';
import '../../../models/product.dart';
import '../../../models/product_option.dart';
import '../../../utils/utils.dart';
import 'options_base.dart';
import 'rules.dart';
class QtyOptions extends OptionsBase {
QtyOptions({@required Product product, @required int index, @required Map<String, dynamic> selections})
: super(product: product, index: index, selections: selections);
@override
State<StatefulWidget> createState() {
return new QtyOptionsState();
}
}
class QtyOptionsState extends OptionsBaseState<QtyOptions> {
Map<String, dynamic> optionsState = new Map<String, dynamic>();
int thisLimitQty = 0;
@override
Widget build(BuildContext context) {
return new ListView.builder(
itemCount: 2,
itemBuilder: (context, index) {
if (index == 0) {
return new Container(
padding: new EdgeInsets.all(10.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
S.of(context).check_option_select_token(product.productAttributes[this.index].name),
style: new TextStyle(
fontSize: 12.5,
),
overflow: TextOverflow.ellipsis,
),
new Text(
product.productAttributes[this.index].required ? S.of(context).check_option_is_required : S.of(context).check_option_is_optional,
style: new TextStyle(
fontSize: 10.0,
color: new Color(0xFF999999)
),
overflow: TextOverflow.ellipsis,
)
],
),
);
}
return _getOptionWidget();
}
);
}
@override
void initState() {
super.initState();
setState(() {
product = widget.product;
selections = widget.selections;
index = widget.index;
});
eventBus.on<OnAttributePageChanged>().listen((event) {
setState(() {
index = event.index;
});
});
}
void _onOptionTappedCallback(name, quantity, adjustAmount, int optIndex, ProductOption productOption) {
Map<String, dynamic> opt = {
'name': name,
'quantity': quantity,
'adjust_amount': adjustAmount
};
var cloneSelections = json.decode(json.encode(selections));
int idx = Utils.selectionsContains(cloneSelections, product.productAttributes[index].name, name);
if (idx != -1) {
if (quantity == 1) {
cloneSelections[product.productAttributes[index].name.toUpperCase()][idx]['quantity'] += 1;
optionsState[product.productAttributes[index].name][optIndex]['quantity'] = cloneSelections[product.productAttributes[index].name.toUpperCase()][idx]['quantity'];
} else {
if (cloneSelections[product.productAttributes[index].name.toUpperCase()][idx]['quantity'] - 1 > 0) {
cloneSelections[product.productAttributes[index].name.toUpperCase()][idx]['quantity'] -= 1;
optionsState[product.productAttributes[index].name][optIndex]['quantity'] = cloneSelections[product.productAttributes[index].name.toUpperCase()][idx]['quantity'];
} else {
(cloneSelections[product.productAttributes[index].name.toUpperCase()] as List).removeAt(idx);
optionsState[product.productAttributes[index].name][optIndex]['quantity'] = 0;
}
}
} else if (cloneSelections.containsKey(product.productAttributes[index].name.toUpperCase())) {
(cloneSelections[product.productAttributes[index].name.toUpperCase()] as List).add(opt);
optionsState[product.productAttributes[index].name][optIndex]['quantity'] = 1;
} else {
cloneSelections[product.productAttributes[index].name.toUpperCase()] = [opt];
optionsState[product.productAttributes[index].name][optIndex]['quantity'] = 1;
}
if (idx != -1 && (cloneSelections[product.productAttributes[index].name.toUpperCase()] as List).length == 0) {
cloneSelections.remove(product.productAttributes[index].name.toUpperCase());
}
setOptionsStateDisabled(product.productAttributes[index].name, false);
setState(() {
selections = cloneSelections;
});
eventBus.fire(new OnAttributeSelectionsChanged(selections));
}
Widget _getOptionWidget() {
var row = Wrap(
children: <Widget>[],
);
List<ProductOption> productOptions = product.productAttributes[index].productOptions;
if (!optionsState.containsKey(product.productAttributes[index].name)) {
List<Map<String, dynamic>> optionState = [];
for (var i = 0; i < productOptions.length; i++) {
int qty = 0;
int idx = Utils.selectionsContains(selections, product.productAttributes[index].name, productOptions[i].name);
if (idx != -1) {
qty = selections[product.productAttributes[index].name.toUpperCase()][idx]['quantity'];
}
optionState.add({'name': product.productAttributes[index].productOptions[i].name, 'disabled': false, 'quantity': qty, 'check': false});
}
optionsState[product.productAttributes[index].name] = optionState;
}
if (selections.containsKey(product.productAttributes[index].name.toUpperCase())) {
Map<String, dynamic> attrExtraJson = Utils.stringToJson(
product.productAttributes[index].extra);
if (attrExtraJson != null) {
var selectLimitIfFieldEqualsTo = Rule.getRule(
attrExtraJson, Rule.RULE_SELECT_LIMIT_IF_FIELD_EQUALS_TO);
if (selectLimitIfFieldEqualsTo != null) {
if (selectLimitIfFieldEqualsTo is List) {
for (var b = 0; b < (selectLimitIfFieldEqualsTo as List).length; b++) {
Map<String, dynamic> selectLimitIfFieldEqualsTo1 = selectLimitIfFieldEqualsTo[b];
if (selectLimitIfFieldEqualsTo1.containsKey(
Rule.RULE_KEY_FORCE_LIMITED)) {
int limitQty = selectLimitIfFieldEqualsTo1[Rule
.RULE_KEY_FORCE_LIMITED];
thisLimitQty = limitQty;
if ((selections[product.productAttributes[index].name
.toUpperCase()] as List).length >= limitQty) {
disableOptionIfNotSelected();
}
} else if (Utils.getSelectedAttributeValue(selections, selectLimitIfFieldEqualsTo1[Rule.RULE_KEY_FIELD_KEY]).length > 0) {
if (selectLimitIfFieldEqualsTo1.containsKey(Utils.getSelectedAttributeValue(selections, selectLimitIfFieldEqualsTo1[Rule.RULE_KEY_FIELD_KEY])[0])) {
int limitQty = selectLimitIfFieldEqualsTo1[Utils.getSelectedAttributeValue(selections, selectLimitIfFieldEqualsTo1[Rule.RULE_KEY_FIELD_KEY])[0]];
thisLimitQty = limitQty;
if ((selections[product.productAttributes[index].name
.toUpperCase()] as List).length >= limitQty) {
disableOptionIfNotSelected();
}
}
}
}
} else {
if (selectLimitIfFieldEqualsTo.containsKey(
Rule.RULE_KEY_FORCE_LIMITED)) {
int limitQty = selectLimitIfFieldEqualsTo[Rule
.RULE_KEY_FORCE_LIMITED];
thisLimitQty = limitQty;
if ((selections[product.productAttributes[index].name
.toUpperCase()] as List).length >= limitQty) {
disableOptionIfNotSelected();
}
} else if (Utils.getSelectedAttributeValue(selections, selectLimitIfFieldEqualsTo[Rule.RULE_KEY_FIELD_KEY]).length > 0) {
if (selectLimitIfFieldEqualsTo.containsKey(Utils.getSelectedAttributeValue(selections, selectLimitIfFieldEqualsTo[Rule.RULE_KEY_FIELD_KEY])[0])) {
int limitQty = selectLimitIfFieldEqualsTo[Utils.getSelectedAttributeValue(selections, selectLimitIfFieldEqualsTo[Rule.RULE_KEY_FIELD_KEY])[0]];
thisLimitQty = limitQty;
if ((selections[product.productAttributes[index].name
.toUpperCase()] as List).length >= limitQty) {
disableOptionIfNotSelected();
}
}
}
}
}
}
for (var i = 0; i < productOptions.length; i++) {
Map<String, dynamic> extraJson = Utils.stringToJson(
productOptions[i].extra);
if (extraJson != null) {
Map<String, dynamic> exclusiveRule = Rule.getRule(
extraJson, Rule.RULE_EXCLUSIVE_SELECTION);
Map<String, dynamic> multiItemRule = Rule.getRule(extraJson, Rule.RULE_ACTUAL_QTY_IS);
if (exclusiveRule != null) {
if (thisLimitQty > 0 && !_checkOptionIsCheck(productOptions[i].name)) {
optionsState[product.productAttributes[index].name][i]['disabled'] = true;
} else {
if (_checkOptionIsCheck(productOptions[i].name)) {
setOptionsStateDisabled(
product.productAttributes[index].name, true);
optionsState[product.productAttributes[index]
.name][i]['disabled'] = false;
break;
}
}
}
if (multiItemRule != null) {
if (_checkOptionIsCheck(productOptions[i].name)) {
if (multiItemRule[Rule.RULE_ACTUAL_QTY_IS] > thisLimitQty - (selections[product.productAttributes[index].name.toUpperCase()] as List).length) {
disableOptionIfNotSelected();
}
} else {
if (multiItemRule[Rule.RULE_ACTUAL_QTY_IS] > thisLimitQty - (selections[product.productAttributes[index].name.toUpperCase()] as List).length) {
optionsState[product.productAttributes[index]
.name][i]['disabled'] = true;
}
}
}
}
}
}
List<Map<String, dynamic>> optionState = optionsState[product.productAttributes[index].name];
for (var i = 0; i < optionState.length; i++) {
Widget optionWidget = _getOptionQty(
product.productAttributes[index].productOptions[i], optionState[i]['disabled'], optionState[i]['quantity'], i);
row.children.add(optionWidget);
}
return row;
}
void disableOptionIfNotSelected() {
setOptionsStateDisabled(product.productAttributes[index].name, true);
for (var i = 0; i < optionsState[product.productAttributes[index].name].length; i++) {
if (Utils.selectionsContains(selections, product.productAttributes[index].name, optionsState[product.productAttributes[index].name][i]['name']) != -1) {
optionsState[product.productAttributes[index].name][i]['disabled'] = false;
}
}
}
bool _checkOptionIsCheck(String name) {
if (Utils.selectionsContains(selections, product.productAttributes[index].name, name) != -1) {
return true;
}
return false;
}
Widget _getOptionQty(ProductOption productOption, bool optDisabled, int quantity, int optIndex) {
bool disabled = optDisabled;
bool check = _checkOptionIsCheck(productOption.name);
Map<String, dynamic> extraJson = Utils.stringToJson(productOption.extra);
// Utils.jsonPrettyPrint(extraJson);
double extraAdjustAmount = 0.0;
if (extraJson != null) {
var sizeBaseAdjustment = Rule.getRule(extraJson, Rule.RULE_ADJUSTMENT_BASED_ON_SELECTED_FIELD_VALUE);
if (sizeBaseAdjustment != null) {
if (sizeBaseAdjustment is List) {
for (var i = 0; i < (sizeBaseAdjustment as List).length; i++) {
Map<String, dynamic> sizeBaseAdjustment1 = sizeBaseAdjustment[i];
List<String> attValues = Utils.getSelectedAttributeValue(selections, sizeBaseAdjustment1[Rule.RULE_KEY_FIELD_KEY]);
if (attValues.length > 0 && sizeBaseAdjustment1.containsKey(attValues[0])) {
extraAdjustAmount += sizeBaseAdjustment1[attValues[0]];
}
}
} else {
List<String> attValues = Utils.getSelectedAttributeValue(selections, sizeBaseAdjustment[Rule.RULE_KEY_FIELD_KEY]);
if (attValues.length > 0 && sizeBaseAdjustment.containsKey(attValues[0])) {
extraAdjustAmount += sizeBaseAdjustment[attValues[0]];
}
}
}
var disabledRule =
Rule.getRule(extraJson, Rule.RULE_DISABLED_IF_FIELD_EQUALS_TO);
if (disabledRule != null) {
if (disabledRule is List) {
for (var i = 0; i < (disabledRule as List).length; i++) {
Map<String, dynamic> disabledRule1 = disabledRule[i];
List<String> attValues = Utils.getSelectedAttributeValue(
selections, disabledRule1[Rule.RULE_KEY_FIELD_KEY]);
if (attValues.length > 0 &&
disabledRule1.containsKey(attValues[0])) {
disabled = true;
}
if (attValues.length > 0) {
for (String s in attValues) {
if (disabledRule1.containsKey(s) && disabledRule1[s]) {
disabled = true;
break;
}
}
}
if (disabled) {
break;
}
}
} else {
List<String> attValues = Utils.getSelectedAttributeValue(
selections, disabledRule[Rule.RULE_KEY_FIELD_KEY]);
if (attValues.length > 0) {
for (String s in attValues) {
if (disabledRule.containsKey(s) && disabledRule[s]) {
disabled = true;
break;
}
}
}
}
}
}
return new Container(
width: 100.0,
height: 100.0,
decoration: BoxDecoration(
color: disabled ? disabledBackgroundColor : (check ? selectedBackgroundColor : deselectBackgroundColor),
shape: BoxShape.rectangle,
border: new Border.all(
color: check ? selectedBorderColor : deselectBorderColor,
width: 1.0,
),
// borderRadius: BorderRadius.all(Radius.circular(10.0)),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0),
),
),
margin: new EdgeInsets.all(10.0).copyWith(right: 0.0),
child: new Column(
children: <Widget>[
new GestureDetector(
child: new Container(
width: 100.0,
height: 70.0,
padding: new EdgeInsets.all(4.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
productOption.name,
style: new TextStyle(
fontSize: 14.0,
color: check ? selectedTextColor : deselectTextColor,
),
maxLines: 2,
softWrap: true,
overflow: TextOverflow.ellipsis,
),
new Text(
(productOption.adjustAmount + extraAdjustAmount) > 0 ? '+${(productOption.adjustAmount + extraAdjustAmount).toStringAsFixed(2)}' : '',
style: new TextStyle(
fontSize: 11.0,
color: check ? selectedTextColor : new Color(0xFFABABAB),
),
overflow: TextOverflow.ellipsis,
)
],
),
),
onTap: () => disabled ? null : _onOptionTappedCallback(
productOption.name, 1, productOption.adjustAmount + extraAdjustAmount, optIndex, productOption),
),
new Container(
width: 100.0,
height: 28.0,
decoration: BoxDecoration(
color: disabled ? disabledBackgroundColor : (check ? selectedBackgroundColor : deselectBackgroundColor),
shape: BoxShape.rectangle,
border: new Border(
top: new BorderSide(
color: check ? selectedBorderColor : deselectBorderColor,
width: 1.0,
),
),
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Expanded(
child: new GestureDetector(
child: new Container(
color: new Color(0x00000000),
width: 49.0,
height: 28.0,
child: new Center(
child: new Text(
'${quantity}',
style: new TextStyle(
color: check ? selectedTextColor : new Color(0xFFABABAB),
),
),
),
),
onTap: () => disabled ? null : _onOptionTappedCallback(
productOption.name, 1, productOption.adjustAmount + extraAdjustAmount, optIndex, productOption),
),
),
new Expanded(
child: new GestureDetector(
child: new Container(
color: disabledBackgroundColor,
width: 49.0,
height: 28.0,
child: new Center(
child: new Text('-')
),
),
onTap: () => (disabled || quantity == 0) ? null : _onOptionTappedCallback(
productOption.name, -1, productOption.adjustAmount + extraAdjustAmount, optIndex, productOption),
),
),
],
),
)
],
),
);
}
void setOptionsStateDisabled(String attrName, bool disabled) {
if (optionsState.containsKey(attrName)) {
List<Map<String, dynamic>> optionState = optionsState[attrName];
for (var i = 0; i < optionState.length; i++) {
optionState[i]['disabled'] = disabled;
}
}
}
}