product edit modal finished
parent
94823fcd56
commit
91e43dbcf4
|
|
@ -25,3 +25,6 @@ linter:
|
|||
|
||||
# Util classes are awesome!
|
||||
avoid_classes_with_only_static_members: true
|
||||
|
||||
# Avoid returning an awaited expression when the expression type is assignable to the function's return type.
|
||||
unnecessary_await_in_return: false
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:satu/core/utils/utils_parse.dart';
|
||||
|
||||
/// user_id : 10
|
||||
/// company_id : 281
|
||||
/// kassa_id : 3
|
||||
|
|
@ -19,13 +21,13 @@ class AuthResponse {
|
|||
|
||||
static AuthResponse fromMap(dynamic map) {
|
||||
final AuthResponse authResponseBean = AuthResponse();
|
||||
authResponseBean.userId = map['user_id'] as int;
|
||||
authResponseBean.companyId = map['company_id'] as int;
|
||||
authResponseBean.kassaId = map['kassa_id'] as int;
|
||||
authResponseBean.token = map['token']?.toString();
|
||||
authResponseBean.authAt = map['auth_at']?.toString();
|
||||
authResponseBean.shard = map['shard'] as int;
|
||||
authResponseBean.message = map['message']?.toString();
|
||||
authResponseBean.userId = cast<int>(map['user_id']);
|
||||
authResponseBean.companyId = cast<int>(map['company_id']);
|
||||
authResponseBean.kassaId = cast<int>(map['kassa_id']);
|
||||
authResponseBean.token = cast<String>(map['token']);
|
||||
authResponseBean.authAt = cast<String>(map['auth_at']);
|
||||
authResponseBean.shard = cast<int>(map['shard']);
|
||||
authResponseBean.message = cast<String>(map['message']);
|
||||
authResponseBean.operation = map['operation'] as bool;
|
||||
return authResponseBean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,35 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class DialogRequest {
|
||||
final String? title;
|
||||
final String? description;
|
||||
final String? buttonTitle;
|
||||
final String? cancelTitle;
|
||||
final String? formatType;
|
||||
|
||||
DialogRequest(
|
||||
{@required this.title,
|
||||
@required this.description,
|
||||
@required this.buttonTitle,
|
||||
{
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.buttonTitle,
|
||||
this.cancelTitle,
|
||||
this.formatType});
|
||||
this.requestPrice,
|
||||
this.requestCount
|
||||
});
|
||||
final String title;
|
||||
final String description;
|
||||
final String buttonTitle;
|
||||
final String? cancelTitle;
|
||||
|
||||
final String? requestPrice;
|
||||
final String? requestCount;
|
||||
|
||||
|
||||
}
|
||||
|
||||
class DialogResponse {
|
||||
//final String fieldOne;
|
||||
//final String fieldTwo;
|
||||
final String? responseText;
|
||||
final bool? confirmed;
|
||||
|
||||
DialogResponse({
|
||||
//this.fieldOne,
|
||||
//this.fieldTwo,
|
||||
this.responseText,
|
||||
this.confirmed,
|
||||
required this.confirmed,
|
||||
this.responsePrice,
|
||||
this.responseCount,
|
||||
});
|
||||
final String? responsePrice;
|
||||
final String? responseCount;
|
||||
final bool confirmed;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ final Logger log = getLogger('SetSellStateAction');
|
|||
|
||||
final DbService _dbService = locator<DbService>();
|
||||
|
||||
ThunkAction<AppState> counterSellItem({required int transactionId, required num counter}) {
|
||||
ThunkAction<AppState> counterOrEditSellItem(
|
||||
{required int transactionId, required num counter, num? price}) {
|
||||
return (Store<AppState> store) async {
|
||||
log.i('counterSellItem');
|
||||
int? appCompanyId = store.state.userState!.auth!.companyId;
|
||||
|
|
@ -36,19 +37,33 @@ ThunkAction<AppState> counterSellItem({required int transactionId, required num
|
|||
|
||||
Transaction? transaction;
|
||||
|
||||
if (uuid != null ) {
|
||||
List<Map<String, dynamic>> set = await _dbService.queryRowsWithWhere(
|
||||
if (uuid != null) {
|
||||
final List<Map<String, dynamic>> set =
|
||||
await _dbService.queryRowsWithWhere(
|
||||
transactionTableName,
|
||||
'$transactionColumnAppCompanyId = ? and $transactionColumnStatus = ? and ${transactionColumnType} = ? and ${transactionColumnId} = ?',
|
||||
[appCompanyId, transactionStatusPrepare, transactionTypeSell, transactionId],
|
||||
'$transactionColumnAppCompanyId = ? '
|
||||
' and $transactionColumnStatus = ? '
|
||||
' and $transactionColumnType = ? '
|
||||
' and $transactionColumnId = ?',
|
||||
[
|
||||
appCompanyId,
|
||||
transactionStatusPrepare,
|
||||
transactionTypeSell,
|
||||
transactionId
|
||||
],
|
||||
orderBy: '$transactionColumnCreatedAt desc');
|
||||
if (set.isNotEmpty) {
|
||||
transaction = Transaction.fromMap(set.first);
|
||||
}
|
||||
}
|
||||
if (transaction != null) {
|
||||
ProductDao item = ProductDao.fromMap(jsonDecode(transaction.data!));
|
||||
final ProductDao item = ProductDao.fromMap(jsonDecode(transaction.data!));
|
||||
if (price != null) {
|
||||
item.price = price;
|
||||
item.count = counter;
|
||||
} else {
|
||||
item.count = (item.count ?? 0) + counter;
|
||||
}
|
||||
transaction.data = jsonEncode(item.toMap());
|
||||
_dbService.update(transactionTableName, transaction.toMap());
|
||||
}
|
||||
|
|
@ -60,21 +75,24 @@ ThunkAction<AppState> counterSellItem({required int transactionId, required num
|
|||
ThunkAction<AppState> addSellItem({required Good good, String? excise}) {
|
||||
return (Store<AppState> store) async {
|
||||
log.i('addSellItem');
|
||||
int? appCompanyId = store.state.userState!.auth!.companyId;
|
||||
final int? appCompanyId = store.state.userState!.auth!.companyId;
|
||||
String? uuid = store.state.sellState!.transactionState!.uuid;
|
||||
|
||||
Transaction? transaction;
|
||||
|
||||
if (uuid != null ) {
|
||||
if (uuid != null) {
|
||||
List<Map<String, dynamic>> set = await _dbService.queryRowsWithWhere(
|
||||
transactionTableName,
|
||||
'$transactionColumnAppCompanyId = ? and $transactionColumnStatus = ? and ${transactionColumnType} = ?',
|
||||
'$transactionColumnAppCompanyId = ? '
|
||||
' and $transactionColumnStatus = ? '
|
||||
' and $transactionColumnType = ?',
|
||||
[appCompanyId, transactionStatusPrepare, transactionTypeSell],
|
||||
orderBy: '$transactionColumnCreatedAt desc');
|
||||
if (set.isNotEmpty) {
|
||||
for (Map<String, dynamic> map in set) {
|
||||
Transaction _transaction = Transaction.fromMap(map);
|
||||
ProductDao _product = ProductDao.fromMap(jsonDecode(_transaction.data!));
|
||||
ProductDao _product =
|
||||
ProductDao.fromMap(jsonDecode(_transaction.data!));
|
||||
if (_product.id == good.id && _product.excise == excise) {
|
||||
transaction = _transaction;
|
||||
break;
|
||||
|
|
@ -100,8 +118,8 @@ ThunkAction<AppState> addSellItem({required Good good, String? excise}) {
|
|||
..excise = excise;
|
||||
//category add logic
|
||||
if (good.categoryId != null) {
|
||||
List<Map<String, dynamic>> set =
|
||||
await _dbService.queryRowsWithWhere(categoryTableName, 'id = ?', [good.categoryId]);
|
||||
List<Map<String, dynamic>> set = await _dbService
|
||||
.queryRowsWithWhere(categoryTableName, 'id = ?', [good.categoryId]);
|
||||
if (set.isNotEmpty) {
|
||||
Category category = Category.fromMap(set.first);
|
||||
item.categoryId = category.id;
|
||||
|
|
@ -131,7 +149,6 @@ ThunkAction<AppState> addSellItem({required Good good, String? excise}) {
|
|||
|
||||
ThunkAction<AppState> removeSellItem({required int transactionId}) {
|
||||
return (Store<AppState> store) async {
|
||||
|
||||
int? appCompanyId = store.state.userState!.auth!.companyId;
|
||||
String? uuid = store.state.sellState!.transactionState!.uuid;
|
||||
|
||||
|
|
@ -179,7 +196,8 @@ Future<void> loadSellData(Store<AppState> store) async {
|
|||
productDao.transactionId = transaction.id;
|
||||
list.add(productDao);
|
||||
}
|
||||
store.dispatch(SetSellStateAction(SellState(items: list, transactionState: TransactionState()..uuid = uuid)));
|
||||
store.dispatch(SetSellStateAction(SellState(
|
||||
items: list, transactionState: TransactionState()..uuid = uuid)));
|
||||
} catch (e, stack) {
|
||||
log.e('loadSellData', e, stack);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:satu/core/models/dialog_models.dart';
|
||||
|
||||
class DialogService {
|
||||
final GlobalKey<NavigatorState> _dialogNavigationKey = GlobalKey<NavigatorState>();
|
||||
final GlobalKey<NavigatorState> _dialogNavigationKey =
|
||||
GlobalKey<NavigatorState>();
|
||||
late Function(DialogRequest)? _showDialogListener;
|
||||
late Function(DialogRequest)? _showDialogInputListener;
|
||||
Completer<DialogResponse>? _dialogCompleter;
|
||||
|
|
@ -22,14 +23,14 @@ class DialogService {
|
|||
|
||||
/// Calls the dialog listener and returns a Future that will wait for dialogComplete.
|
||||
Future<DialogResponse> showDialog({
|
||||
String title = 'Aman Касса',
|
||||
String title = 'SATU',
|
||||
String? description,
|
||||
String buttonTitle = 'Ok',
|
||||
}) {
|
||||
_dialogCompleter = Completer<DialogResponse>();
|
||||
_showDialogListener!(DialogRequest(
|
||||
title: title,
|
||||
description: description,
|
||||
description: description ?? '',
|
||||
buttonTitle: buttonTitle,
|
||||
));
|
||||
return _dialogCompleter!.future;
|
||||
|
|
@ -43,26 +44,29 @@ class DialogService {
|
|||
String cancelTitle = 'Cancel'}) {
|
||||
_dialogCompleter = Completer<DialogResponse>();
|
||||
_showDialogListener!(DialogRequest(
|
||||
title: title,
|
||||
description: description,
|
||||
title: title ?? '',
|
||||
description: description ?? '',
|
||||
buttonTitle: confirmationTitle,
|
||||
cancelTitle: cancelTitle));
|
||||
return _dialogCompleter!.future;
|
||||
}
|
||||
|
||||
Future<DialogResponse> showConfirmationDialogInput(
|
||||
{String title = ' Aman Касса',
|
||||
Future<DialogResponse> showConfirmationDialogInput({
|
||||
required String title,
|
||||
required String requestPrice,
|
||||
required String requestCount,
|
||||
String? description,
|
||||
String confirmationTitle = 'Ok',
|
||||
String cancelTitle = 'Cancel',
|
||||
String? formatType}) {
|
||||
String confirmationTitle = 'ПОДТВЕРДИТЬ',
|
||||
String cancelTitle = 'Отмена',
|
||||
}) {
|
||||
_dialogCompleter = Completer<DialogResponse>();
|
||||
_showDialogInputListener!(DialogRequest(
|
||||
title: title,
|
||||
description: description,
|
||||
description: description ?? '',
|
||||
buttonTitle: confirmationTitle,
|
||||
cancelTitle: cancelTitle,
|
||||
formatType: formatType));
|
||||
requestPrice: requestPrice,
|
||||
requestCount: requestCount));
|
||||
return _dialogCompleter!.future;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,3 +4,15 @@ List<String>? parseListString(Iterable<dynamic>? json){
|
|||
}
|
||||
|
||||
T? cast<T>(x) => x is T ? x : null;
|
||||
|
||||
bool isNumeric(String? s) {
|
||||
if (s == null) {
|
||||
return false;
|
||||
}
|
||||
return double.tryParse(s) != null;
|
||||
}
|
||||
|
||||
String formatDecimal(double value) {
|
||||
if (value % 1 == 0) return value.toStringAsFixed(0).toString();
|
||||
return value.toString();
|
||||
}
|
||||
|
|
@ -3,38 +3,37 @@ import 'package:flutter/material.dart';
|
|||
import 'app_colors.dart';
|
||||
|
||||
// Box Decorations
|
||||
BoxDecoration fieldDecoration = BoxDecoration(color: whiteColor);
|
||||
BoxDecoration fieldDecoration = const BoxDecoration(color: whiteColor);
|
||||
BoxDecoration disabledFieldDecoration = BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5), color: Colors.grey[100]);
|
||||
|
||||
const LinearGradient primaryGradient = LinearGradient(
|
||||
LinearGradient primaryGradient = const LinearGradient(
|
||||
colors: [
|
||||
primaryGrStartColor,
|
||||
primaryGrEndColor,
|
||||
],
|
||||
begin: const FractionalOffset(0.0, 0.0),
|
||||
end: const FractionalOffset(1.0, 0.0),
|
||||
stops: [0.0, 1.0],
|
||||
tileMode: TileMode.clamp);
|
||||
begin: FractionalOffset(0.0, 0.0),
|
||||
end: FractionalOffset(1.0, 0.0),
|
||||
stops: [0.0, 1.0]);
|
||||
|
||||
// Field Variables
|
||||
const double fieldHeight = 55;
|
||||
const double smallFieldHeight = 40;
|
||||
const double inputFieldBottomMargin = 30;
|
||||
const double inputFieldSmallBottomMargin = 0;
|
||||
const EdgeInsets fieldPadding = const EdgeInsets.symmetric(horizontal: 8.0);
|
||||
const EdgeInsets largeFieldPadding =
|
||||
EdgeInsets fieldPadding = const EdgeInsets.symmetric(horizontal: 8.0);
|
||||
EdgeInsets largeFieldPadding =
|
||||
const EdgeInsets.symmetric(horizontal: 15, vertical: 15);
|
||||
|
||||
// Text Variables
|
||||
|
||||
|
||||
|
||||
const TextStyle dropDownTradeTypeTextStyle =
|
||||
TextStyle(color: Colors.black54, fontWeight: FontWeight.bold, fontSize: 24);
|
||||
|
||||
// Box Shadow
|
||||
const BoxShadow buttonShadowBox =
|
||||
BoxShadow(blurRadius: 10, color: shadowColor, offset: Offset(0, 4));
|
||||
const BoxShadow cardShadowBox =
|
||||
BoxShadow(blurRadius: 3, color: Color.fromRGBO(0, 0, 0, 0.15), offset: Offset(0, 1));
|
||||
BoxShadow buttonShadowBox =
|
||||
const BoxShadow(blurRadius: 10, color: shadowColor, offset: Offset(0, 4));
|
||||
BoxShadow inputShadowBox =
|
||||
const BoxShadow(blurRadius: 1, color: shadowColor, offset: Offset(0, 2));
|
||||
BoxShadow cardShadowBox = const BoxShadow(
|
||||
blurRadius: 3, color: Color.fromRGBO(0, 0, 0, 0.15), offset: Offset(0, 1));
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
import 'dart:ffi';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:satu/core/models/dialog_models.dart';
|
||||
import 'package:satu/core/redux/actions/sell_actions.dart';
|
||||
import 'package:satu/core/redux/store.dart';
|
||||
import 'package:satu/core/services/dialog_service.dart';
|
||||
import 'package:satu/core/services/navigator_service.dart';
|
||||
import 'package:satu/core/utils/locator.dart';
|
||||
import 'package:satu/core/utils/utils_parse.dart';
|
||||
import 'package:satu/routes/route_names.dart';
|
||||
import 'package:satu/shared/app_colors.dart';
|
||||
import 'package:satu/shared/shared_styles.dart';
|
||||
|
|
@ -16,6 +20,17 @@ import 'package:satu/widgets/ui/product_title_widget.dart';
|
|||
import 'dialog_edit_product.dart';
|
||||
|
||||
class ProductListItem extends StatefulWidget {
|
||||
const ProductListItem(
|
||||
{Key? key,
|
||||
this.name = '',
|
||||
this.ean,
|
||||
this.categoryName,
|
||||
this.price,
|
||||
this.count,
|
||||
this.isOdd,
|
||||
this.transactionId})
|
||||
: super(key: key);
|
||||
|
||||
final String name;
|
||||
final String? ean;
|
||||
final String? categoryName;
|
||||
|
|
@ -24,10 +39,6 @@ class ProductListItem extends StatefulWidget {
|
|||
final bool? isOdd;
|
||||
final int? transactionId;
|
||||
|
||||
const ProductListItem(
|
||||
{Key? key, this.name = '', this.ean, this.categoryName, this.price, this.count, this.isOdd, this.transactionId})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_ProductListItemState createState() => _ProductListItemState();
|
||||
}
|
||||
|
|
@ -38,7 +49,7 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
|
||||
void _onItemTapped(BuildContext context) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (BuildContext context) => AddByBarcodeView()));
|
||||
builder: (BuildContext context) => const AddByBarcodeView()));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -61,13 +72,17 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text("Внимание"),
|
||||
content: Text("Удалить товар \"${this.widget.name}\" - ${widget.count} ед. ?"),
|
||||
title: const Text('Внимание'),
|
||||
content: Text('Удалить товар '
|
||||
'"${widget.name}"'
|
||||
' - ${widget.count} ед. ?'),
|
||||
actions: <Widget>[
|
||||
TextButton(onPressed: () => Navigator.of(context).pop(true), child: const Text("Удалить")),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: const Text('Удалить')),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: const Text("Отмена"),
|
||||
child: const Text('Отмена'),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
@ -75,19 +90,25 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
);
|
||||
},
|
||||
onDismissed: (direction) {
|
||||
Redux.store!.dispatch(removeSellItem(transactionId: this.widget.transactionId!));
|
||||
Redux.store!
|
||||
.dispatch(removeSellItem(transactionId: widget.transactionId!));
|
||||
},
|
||||
key: Key(widget.name ),
|
||||
key: Key(widget.name),
|
||||
child: ListTile(
|
||||
//onTap: () => _onItemTapped(context),
|
||||
onTap: () {},
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 4.0),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 10.0, vertical: 4.0),
|
||||
title: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ProductTitleWidget(name: widget.name, ean: widget.ean, categoryName: widget.categoryName, ),
|
||||
child: ProductTitleWidget(
|
||||
name: widget.name,
|
||||
ean: widget.ean,
|
||||
categoryName: widget.categoryName,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 100.w,
|
||||
|
|
@ -98,7 +119,10 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
padding: const EdgeInsets.only(bottom: 3.0),
|
||||
child: Text(
|
||||
'${widget.price} ₸',
|
||||
style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.w500, color: textColor),
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: textColor),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
|
|
@ -106,17 +130,21 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
children: [
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(ScreenUtil().radius(5)),
|
||||
borderRadius:
|
||||
BorderRadius.circular(ScreenUtil().radius(5)),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Redux.store!
|
||||
.dispatch(counterSellItem(transactionId: widget.transactionId!, counter: 1.0));
|
||||
Redux.store!.dispatch(counterOrEditSellItem(
|
||||
transactionId: widget.transactionId!,
|
||||
counter: 1.0));
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
//color: whiteColor,
|
||||
borderRadius: BorderRadius.circular(ScreenUtil().radius(5)),
|
||||
border: Border.all(width: 1.0.sp, color: successColor)),
|
||||
borderRadius: BorderRadius.circular(
|
||||
ScreenUtil().radius(5)),
|
||||
border: Border.all(
|
||||
width: 1.0.sp, color: successColor)),
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: successColor,
|
||||
|
|
@ -130,11 +158,12 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
margin: EdgeInsets.symmetric(horizontal: 5.w),
|
||||
decoration: BoxDecoration(
|
||||
color: whiteColor,
|
||||
borderRadius: BorderRadius.circular(ScreenUtil().radius(5)),
|
||||
borderRadius:
|
||||
BorderRadius.circular(ScreenUtil().radius(5)),
|
||||
boxShadow: [cardShadowBox]),
|
||||
child: InkWell(
|
||||
onTap: (){
|
||||
_dialogService.showConfirmationDialogInput(description: 'asd');
|
||||
onTap: () {
|
||||
editProductModal();
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 6.0.w),
|
||||
|
|
@ -142,7 +171,8 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
width: 45.w,
|
||||
child: Text(
|
||||
'${widget.count} шт',
|
||||
style: TextStyle(fontSize: 8.sp, color: placeholderColor),
|
||||
style: TextStyle(
|
||||
fontSize: 10.sp, color: placeholderColor),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
|
|
@ -151,23 +181,31 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(ScreenUtil().radius(5)),
|
||||
borderRadius:
|
||||
BorderRadius.circular(ScreenUtil().radius(5)),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (widget.count! > 1.0) {
|
||||
Redux.store!
|
||||
.dispatch(counterSellItem(transactionId: this.widget.transactionId!, counter: -1.0));
|
||||
Redux.store!.dispatch(counterOrEditSellItem(
|
||||
transactionId: widget.transactionId!,
|
||||
counter: -1.0));
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
//color: whiteColor,
|
||||
borderRadius: BorderRadius.circular(ScreenUtil().radius(5)),
|
||||
borderRadius: BorderRadius.circular(
|
||||
ScreenUtil().radius(5)),
|
||||
border: Border.all(
|
||||
width: 1.0.sp, color: widget.count! <= 1.0 ? disableColor : dangerColor)),
|
||||
width: 1.0.sp,
|
||||
color: widget.count! <= 1.0
|
||||
? disableColor
|
||||
: dangerColor)),
|
||||
child: Icon(
|
||||
Icons.remove,
|
||||
color: widget.count! <= 1.0 ? disableColor : dangerColor,
|
||||
color: widget.count! <= 1.0
|
||||
? disableColor
|
||||
: dangerColor,
|
||||
size: 20.0.sp,
|
||||
),
|
||||
),
|
||||
|
|
@ -184,6 +222,24 @@ class _ProductListItemState extends State<ProductListItem> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> editProductModal() async {
|
||||
final DialogResponse response =
|
||||
await _dialogService.showConfirmationDialogInput(
|
||||
title: widget.name,
|
||||
requestCount: formatDecimal(widget.count!.toDouble()),
|
||||
requestPrice: formatDecimal(widget.price!.toDouble()));
|
||||
if (response.confirmed) {
|
||||
if (isNumeric(response.responsePrice) &&
|
||||
isNumeric(response.responseCount)) {
|
||||
Redux.store!.dispatch(counterOrEditSellItem(
|
||||
transactionId: widget.transactionId!,
|
||||
counter: num.parse(response.responseCount!),
|
||||
price: num.parse(response.responsePrice!),
|
||||
));
|
||||
} else {
|
||||
_dialogService.showDialog(description: 'Не верный формат');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -37,20 +37,20 @@ class _BusyButtonState extends State<BusyButton> {
|
|||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if(!(widget.busy || !widget.enabled))
|
||||
widget.onPressed();
|
||||
if (!(widget.busy || !widget.enabled)) widget.onPressed();
|
||||
},
|
||||
child: AnimatedContainer(
|
||||
height: 40.h,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
alignment: Alignment.center,
|
||||
//margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0 ),
|
||||
child: !widget.busy
|
||||
? Text(
|
||||
widget.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400, color: blackColor, fontSize: 12.sp ),
|
||||
fontWeight: FontWeight.w400,
|
||||
color: blackColor,
|
||||
fontSize: 14.sp),
|
||||
//minFontSize: 2,
|
||||
maxLines: 1,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';
|
||||
import 'package:satu/core/models/dialog_models.dart';
|
||||
import 'package:satu/core/services/dialog_service.dart';
|
||||
import 'package:satu/core/utils/locator.dart';
|
||||
import 'package:satu/shared/app_colors.dart';
|
||||
import 'package:satu/shared/ui_helpers.dart';
|
||||
import 'package:satu/widgets/buttons/busy_button.dart';
|
||||
import 'package:satu/widgets/fields/input_field.dart';
|
||||
import 'package:satu/widgets/fields/input_field_rounded.dart';
|
||||
|
||||
class DialogManager extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
|
@ -15,18 +22,21 @@ class DialogManager extends StatefulWidget {
|
|||
|
||||
class _DialogManagerState extends State<DialogManager> {
|
||||
final DialogService _dialogService = locator<DialogService>();
|
||||
late TextEditingController _controller;
|
||||
late TextEditingController _controllerPrice;
|
||||
late TextEditingController _controllerCount;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = new TextEditingController();
|
||||
_controllerPrice = TextEditingController();
|
||||
_controllerCount = TextEditingController();
|
||||
_dialogService.registerDialogListener(_showDialog, _showDialogInput);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
_controllerPrice.dispose();
|
||||
_controllerCount.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +46,6 @@ class _DialogManagerState extends State<DialogManager> {
|
|||
}
|
||||
|
||||
void _showDialog(DialogRequest request) {
|
||||
|
||||
var isConfirmationDialog = request.cancelTitle != null;
|
||||
showDialog<String>(
|
||||
context: context,
|
||||
|
|
@ -49,13 +58,13 @@ class _DialogManagerState extends State<DialogManager> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
request.title!,
|
||||
request.title,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
//Divider(),
|
||||
],
|
||||
),
|
||||
content: Text(request.description!),
|
||||
content: Text(request.description),
|
||||
actions: <Widget>[
|
||||
if (isConfirmationDialog)
|
||||
TextButton(
|
||||
|
|
@ -70,95 +79,95 @@ class _DialogManagerState extends State<DialogManager> {
|
|||
_dialogService
|
||||
.dialogComplete(DialogResponse(confirmed: true));
|
||||
},
|
||||
child: Text(request.buttonTitle!),
|
||||
child: Text(request.buttonTitle),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
void _showDialogInput(DialogRequest request) {
|
||||
var isConfirmationDialog = request.cancelTitle != null;
|
||||
final bool isConfirmationDialog = request.cancelTitle != null;
|
||||
|
||||
_controller.clear();
|
||||
_controllerPrice.text = request.requestPrice ?? '';
|
||||
_controllerCount.text = request.requestCount ?? '';
|
||||
|
||||
var maskFormatter = new MaskTextInputFormatter(
|
||||
mask: '+% (###) ###-##-##',
|
||||
filter: {"#": RegExp(r'[0-9]'), "%": RegExp(r'[7]')});
|
||||
|
||||
var dialogController = showDialog(
|
||||
final dialogController = showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
backgroundColor: backgroundColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
actionsPadding: const EdgeInsets.only(right: 15, bottom: 5),
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
request.title!,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
//Divider(),
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
content: SizedBox(
|
||||
width: ScreenUtil().setWidth(ScreenUtil().screenWidth * 0.9),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
//Text(request.description),
|
||||
TextField(
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(
|
||||
labelText: request.description,
|
||||
hintText: request.formatType == "phone"
|
||||
? "+7 (123) 456-78-90"
|
||||
: ""),
|
||||
controller: _controller,
|
||||
onSubmitted: (value) {
|
||||
_dialogService
|
||||
.dialogComplete(DialogResponse(confirmed: false));
|
||||
Text(
|
||||
request.title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: ScreenUtil().setSp(14)),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
verticalSpaceSmall,
|
||||
const Divider(),
|
||||
verticalSpaceSmall,
|
||||
InputFieldRounded(
|
||||
controller: _controllerPrice,
|
||||
placeholder: '',
|
||||
suffixText: '₸',
|
||||
labelText: 'Стоимость товара',
|
||||
textInputType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
),
|
||||
InputFieldRounded(
|
||||
textInputType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
controller: _controllerCount,
|
||||
placeholder: '',
|
||||
suffixText: 'шт',
|
||||
labelText: 'Количество товара',
|
||||
),
|
||||
verticalSpaceSmall,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (isConfirmationDialog)
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
_dialogService.dialogComplete(
|
||||
DialogResponse(confirmed: false));
|
||||
},
|
||||
keyboardType: TextInputType.phone,
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
if (request.formatType == "phone") maskFormatter,
|
||||
if (request.formatType == null)
|
||||
FilteringTextInputFormatter.allow(RegExp("^[0-9.]*")),
|
||||
//color: redColor,
|
||||
child: Text(
|
||||
request.cancelTitle!,
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: placeholderColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: BusyButton(
|
||||
title: request.buttonTitle,
|
||||
onPressed: () {
|
||||
final String _price = _controllerPrice.text;
|
||||
final String _count = _controllerCount.text;
|
||||
_dialogService.dialogComplete(DialogResponse(
|
||||
confirmed: true,
|
||||
responsePrice: _price.replaceAll(',', '.'),
|
||||
responseCount: _count.replaceAll(',', '.')));
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
actions: <Widget>[
|
||||
if (isConfirmationDialog)
|
||||
RaisedButton(
|
||||
//color: redColor,
|
||||
child: Text(
|
||||
request.cancelTitle!,
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
onPressed: () {
|
||||
_dialogService
|
||||
.dialogComplete(DialogResponse(confirmed: false));
|
||||
},
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
RaisedButton(
|
||||
//color: primaryColor,
|
||||
child: Text(
|
||||
request.buttonTitle!,
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
onPressed: () {
|
||||
String _result = _controller.text;
|
||||
if (request.formatType == "phone") {
|
||||
_result = maskFormatter.getUnmaskedText();
|
||||
}
|
||||
_dialogService.dialogComplete(
|
||||
DialogResponse(confirmed: true, responseText: _result));
|
||||
},
|
||||
),
|
||||
],
|
||||
));
|
||||
dialogController.whenComplete(() {
|
||||
//hook when press overlay and response not completed
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:satu/shared/app_colors.dart';
|
||||
import 'package:satu/shared/shared_styles.dart';
|
||||
import 'package:satu/shared/ui_helpers.dart';
|
||||
|
||||
import 'note_text.dart';
|
||||
|
||||
class InputFieldRounded extends StatefulWidget {
|
||||
final TextEditingController controller;
|
||||
final TextInputType textInputType;
|
||||
final bool password;
|
||||
final bool search;
|
||||
final bool isReadOnly;
|
||||
final String placeholder;
|
||||
final String? validationMessage;
|
||||
final Function? enterPressed;
|
||||
final bool smallVersion;
|
||||
final FocusNode? fieldFocusNode;
|
||||
final FocusNode? nextFocusNode;
|
||||
final TextInputAction textInputAction;
|
||||
final bool multiline;
|
||||
final String? additionalNote;
|
||||
final Function(String)? onChanged;
|
||||
final TextInputFormatter? formatter;
|
||||
final String? initialValue;
|
||||
final String? labelText;
|
||||
final String? suffixText;
|
||||
|
||||
InputFieldRounded(
|
||||
{required this.controller,
|
||||
required this.placeholder,
|
||||
this.enterPressed,
|
||||
this.fieldFocusNode,
|
||||
this.nextFocusNode,
|
||||
this.additionalNote,
|
||||
this.onChanged,
|
||||
this.formatter,
|
||||
this.suffixText,
|
||||
this.initialValue,
|
||||
this.validationMessage,
|
||||
this.textInputAction = TextInputAction.next,
|
||||
this.textInputType = TextInputType.text,
|
||||
this.password = false,
|
||||
this.search = false,
|
||||
this.isReadOnly = false,
|
||||
this.multiline = false,
|
||||
this.smallVersion = false,
|
||||
this.labelText});
|
||||
|
||||
@override
|
||||
_InputFieldRoundedState createState() => _InputFieldRoundedState();
|
||||
}
|
||||
|
||||
class _InputFieldRoundedState extends State<InputFieldRounded> {
|
||||
late bool isPassword;
|
||||
late bool isSearch;
|
||||
double fieldHeight = 40;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
isPassword = widget.password;
|
||||
isSearch = widget.search;
|
||||
if (widget.search == true) {
|
||||
widget.fieldFocusNode!.addListener(() {
|
||||
if (widget.fieldFocusNode!.hasFocus) {
|
||||
setState(() {
|
||||
isSearch = !isSearch;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
if (widget.labelText != null)
|
||||
NoteText(
|
||||
widget.labelText ?? '',
|
||||
fontSize: ScreenUtil().setSp(14),
|
||||
),
|
||||
if (widget.labelText != null) verticalSpace(5),
|
||||
Container(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: widget.smallVersion ? 40.h : fieldHeight),
|
||||
alignment: Alignment.centerLeft,
|
||||
padding: fieldPadding,
|
||||
decoration:
|
||||
widget.isReadOnly ? disabledFieldDecoration : BoxDecoration( color: whiteColor , borderRadius: BorderRadius.circular(6.0), boxShadow: [
|
||||
inputShadowBox
|
||||
]),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (isSearch) {
|
||||
widget.fieldFocusNode!.requestFocus();
|
||||
} else {
|
||||
setState(() {
|
||||
isSearch = !isSearch;
|
||||
});
|
||||
FocusScope.of(context)
|
||||
.requestFocus(new FocusNode()); //remove focus
|
||||
WidgetsBinding.instance!.addPostFrameCallback(
|
||||
(_) => widget.controller.clear()); // clear content
|
||||
}
|
||||
},
|
||||
child: widget.search
|
||||
? Container(
|
||||
width: fieldHeight,
|
||||
height: fieldHeight,
|
||||
alignment: Alignment.center,
|
||||
child: Icon(isSearch ? Icons.search : Icons.search_off,
|
||||
color: placeholderColor))
|
||||
: Container(),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: widget.smallVersion
|
||||
? ScreenUtil().setSp(12)
|
||||
: ScreenUtil().setSp(15)),
|
||||
controller: widget.controller,
|
||||
keyboardType: widget.textInputType,
|
||||
focusNode: widget.fieldFocusNode,
|
||||
textInputAction: widget.textInputAction,
|
||||
maxLines: widget.multiline ? null : 1,
|
||||
onChanged: widget.onChanged,
|
||||
initialValue: widget.initialValue,
|
||||
inputFormatters:
|
||||
widget.formatter != null ? [widget.formatter!] : null,
|
||||
onEditingComplete: () {
|
||||
if (widget.enterPressed != null) {
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
widget.enterPressed!();
|
||||
}
|
||||
},
|
||||
onFieldSubmitted: (value) {
|
||||
if (widget.nextFocusNode != null) {
|
||||
widget.nextFocusNode!.requestFocus();
|
||||
}
|
||||
},
|
||||
obscureText: isPassword,
|
||||
readOnly: widget.isReadOnly,
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.placeholder,
|
||||
filled: true,
|
||||
fillColor: whiteColor,
|
||||
border: InputBorder.none,
|
||||
suffixText: widget.suffixText,
|
||||
hintStyle: TextStyle(
|
||||
fontSize: widget.smallVersion
|
||||
? ScreenUtil().setSp(12)
|
||||
: ScreenUtil().setSp(15),
|
||||
color: placeholderColor)),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => setState(() {
|
||||
isPassword = !isPassword;
|
||||
}),
|
||||
child: widget.password
|
||||
? Container(
|
||||
width: fieldHeight,
|
||||
height: fieldHeight,
|
||||
alignment: Alignment.center,
|
||||
child: Icon(
|
||||
isPassword
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
color: textColor))
|
||||
: Container(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (widget.validationMessage != null)
|
||||
NoteText(
|
||||
widget.validationMessage ?? '',
|
||||
color: dangerColor,
|
||||
),
|
||||
if (widget.additionalNote != null) verticalSpace(5),
|
||||
if (widget.additionalNote != null)
|
||||
NoteText(widget.additionalNote ?? ''),
|
||||
verticalSpaceSmall
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
|
|||
import 'package:satu/shared/app_colors.dart';
|
||||
|
||||
class NoteText extends StatelessWidget {
|
||||
const NoteText(this.text, {this.textAlign, this.color, this.fontSize});
|
||||
final String text;
|
||||
final TextAlign? textAlign;
|
||||
final Color? color;
|
||||
final double? fontSize;
|
||||
const NoteText(this.text, {this.textAlign, this.color, this.fontSize});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -18,20 +18,20 @@ class ProductTitleWidget extends StatelessWidget {
|
|||
children: [
|
||||
Text(
|
||||
name,
|
||||
style: TextStyle(fontSize: 12.sp, color: textColor),
|
||||
style: TextStyle(fontSize: 14.sp, color: textColor),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
),
|
||||
verticalSpaceTiny,
|
||||
if (ean != null)
|
||||
Text(
|
||||
'Штрих-код: ${ean}',
|
||||
style: TextStyle(color: placeholderColor, fontSize: 8.sp),
|
||||
'Штрих-код: $ean',
|
||||
style: TextStyle(color: placeholderColor, fontSize: 10.sp),
|
||||
),
|
||||
if (categoryName != null)
|
||||
Text(
|
||||
'Категория: ${categoryName}',
|
||||
style: TextStyle(color: placeholderColor, fontSize: 8.sp),
|
||||
'Категория: $categoryName',
|
||||
style: TextStyle(color: placeholderColor, fontSize: 10.sp),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue