payment combine dock

null-safety-migration
suvaissov 2021-07-22 14:56:08 +06:00
parent 8d162bf19b
commit fe99db18b4
16 changed files with 421 additions and 149 deletions

View File

@ -50,9 +50,9 @@ class AppState {
//stable work
AppState copyWith({
@required UserState? userState,
@required NavState? navState,
@required SellState? sellState,
UserState? userState,
NavState? navState,
SellState? sellState,
}) {
return AppState(
userState: userState ?? this.userState,

View File

@ -91,7 +91,7 @@ class _AddProductViewState extends State<AddProductView> {
ean: good.ean,
name: good.name,
price: good.price,
categoryName: _history?.last?.name,
categoryName: _history?.last.name,
onPress: () {
onGoodPress(good);
} ,

View File

@ -0,0 +1,111 @@
import 'package:flutter/material.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class CombineDock extends StatelessWidget {
const CombineDock({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
verticalSpaceSmall,
const Padding(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 8.0),
child: Text(
'Расчет',
style: TextStyle(fontSize: 12, color: placeholderColor),
),
),
Container(
decoration: const BoxDecoration(
color: whiteColor,
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'К оплате',
style: TextStyle(
fontSize: 14,
),
),
Text(
'1200 ₸',
style: TextStyle(fontSize: 20),
),
],
),
),
const Divider(
height: 1,
color: disableColor,
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Банковская карта',
style:
TextStyle(fontSize: 12, color: placeholderColor),
),
Text(
'1200 ₸',
style:
TextStyle(fontSize: 12, color: placeholderColor),
),
],
),
verticalSpaceSmall,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Наличными',
style:
TextStyle(fontSize: 12, color: placeholderColor),
),
Text(
'0 ₸',
style:
TextStyle(fontSize: 12, color: placeholderColor),
),
],
),
verticalSpaceSmall,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Сдача',
style:
TextStyle(fontSize: 12, color: placeholderColor),
),
Text(
'0 ₸',
style:
TextStyle(fontSize: 12, color: placeholderColor),
),
],
)
],
),
),
],
),
)
],
);
}
}

View File

@ -1,15 +1,17 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/utils/utils_parse.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/views/work/views/payment/component/combine_dock.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/bar/products_header_bar.dart';
import 'package:satu/widgets/bar/products_title_bar.dart';
import 'package:satu/views/work/tabs/utils/product_utils.dart';
import 'package:satu/widgets/buttons/busy_button.dart';
import 'package:satu/widgets/fields/input_field.dart';
import 'package:satu/widgets/fields/line_checkbox.dart';
class PaymentView extends StatefulWidget {
@override
@ -17,7 +19,26 @@ class PaymentView extends StatefulWidget {
}
class _PaymentViewState extends State<PaymentView> {
bool combine = false;
bool combine = true;
late num _sum;
late TextEditingController _bankSumCtrl;
late TextEditingController _cashSumCtrl;
@override
void initState() {
super.initState();
_sum = sumProducts(Redux.store!.state.sellState!.items!);
_bankSumCtrl = TextEditingController(text: formatDecimal(_sum.toDouble()));
_cashSumCtrl = TextEditingController(text: '0');
}
@override
void dispose() {
_bankSumCtrl.dispose();
_cashSumCtrl.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
@ -31,27 +52,31 @@ class _PaymentViewState extends State<PaymentView> {
childHeight: 60,
child: ProductHeaderBar(
count: state.items!.length,
sum: sumProducts(state.items!),
sum: _sum,
),
),
body: ListView(
physics: const BouncingScrollPhysics(),
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 15.w),
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
Visibility(
visible: combine == false,
child: const Text(
'Способ оплаты',
style: TextStyle(
fontSize: 16.sp, color: placeholderColor),
style:
TextStyle(fontSize: 14, color: placeholderColor),
),
),
Row(
children: [
Text(
'Комбинированный',
style: TextStyle(fontSize: 14.sp, color: placeholderColor),
const Text(
'комбинированный',
style: TextStyle(
fontSize: 12, color: placeholderColor),
),
Switch(
value: combine,
@ -66,8 +91,10 @@ class _PaymentViewState extends State<PaymentView> {
],
),
),
buildPaymentSelect(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 45.0),
padding:
const EdgeInsets.symmetric(horizontal: 45, vertical: 30),
child: BusyButton(title: 'ОПЛАТА', onPressed: () {}),
),
],
@ -75,4 +102,44 @@ class _PaymentViewState extends State<PaymentView> {
);
});
}
Column buildPaymentSelect() {
if (combine) {
return Column(
children: [
InputField(
controller: _bankSumCtrl,
labelText: 'Банковская карта',
placeholder: 'Укажите сумму',
suffixText: '',
textInputType: const TextInputType.numberWithOptions(decimal: true),
),
InputField(
controller: _cashSumCtrl,
labelText: 'Наличные',
placeholder: 'Укажите сумму наличных',
suffixText: '',
textInputType: const TextInputType.numberWithOptions(decimal: true),
),
const CombineDock()
],
);
}
return Column(
children: const [
LineCheckBox(
'Банковская карта',
value: true,
),
Divider(
height: 1,
color: disableColor,
),
LineCheckBox(
'Оплата наличными',
value: false,
),
],
);
}
}

View File

@ -10,7 +10,9 @@ class ProductsTitleBarBar extends StatelessWidget {
final bool itemsExist;
final String title;
const ProductsTitleBarBar({Key? key, this.itemsExist = false, required this.title}) : super(key: key);
const ProductsTitleBarBar(
{Key? key, this.itemsExist = false, required this.title})
: super(key: key);
@override
Widget build(BuildContext context) {
@ -30,24 +32,28 @@ class ProductsTitleBarBar extends StatelessWidget {
if (itemsExist)
TextButton(
onPressed: () async {
bool? result = await showDialog(
final bool? result = await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Внимание"),
content: Text("Удалить все товары из списка"),
title: const Text('Внимание'),
content: const Text('Удалить все товары из списка'),
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('Отмена'),
),
],
);
},
);
if(result == true)
if (result == true) {
Redux.store!.dispatch(removeAllSellData);
}
},
child: Text(
'Удалить все',

View File

@ -5,21 +5,21 @@ import 'package:satu/shared/shared_styles.dart';
/// A button that shows a busy indicator in place of title
class AmanIconButton extends StatefulWidget {
const AmanIconButton({
required this.title,
required this.onPressed,
required this.mainColor,
required this.icon,
this.busy = false,
this.enabled = true,
});
final bool busy;
final String title;
final Function onPressed;
final bool? enabled;
final Color mainColor;
final IconData icon;
const AmanIconButton(
{
required this.title,
this.busy = false,
required this.onPressed,
this.enabled = true,
required this.mainColor,
required this.icon
});
@override
_AmanIconButtonState createState() => _AmanIconButtonState();
@ -40,13 +40,10 @@ class _AmanIconButtonState extends State<AmanIconButton> {
//height: 75,
width: 120,
alignment: Alignment.center,
padding: EdgeInsets.symmetric(
//horizontal: 25,
vertical: 15),
padding: const EdgeInsets.symmetric(vertical: 15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
border: Border.all( width: 1.0, color: widget.mainColor )
),
border: Border.all(width: 1.0, color: widget.mainColor)),
child: Column(
children: <Widget>[
(!widget.busy
@ -57,8 +54,19 @@ class _AmanIconButtonState extends State<AmanIconButton> {
)
: CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation<Color>(widget.mainColor))),
AutoSizeText(widget.title, overflow: TextOverflow.fade, maxLines: 2, style: TextStyle(color: widget.mainColor, fontSize: 14, fontWeight: FontWeight.w800, ), textAlign: TextAlign.center,)
valueColor:
AlwaysStoppedAnimation<Color>(widget.mainColor))),
AutoSizeText(
widget.title,
overflow: TextOverflow.fade,
maxLines: 2,
style: TextStyle(
color: widget.mainColor,
fontSize: 14,
fontWeight: FontWeight.w800,
),
textAlign: TextAlign.center,
)
],
),
),

View File

@ -47,17 +47,17 @@ class _BusyButtonState extends State<BusyButton> {
? Text(
widget.title,
textAlign: TextAlign.center,
style: TextStyle(
style: const TextStyle(
fontWeight: FontWeight.w400,
color: blackColor,
fontSize: 14.sp),
fontSize: 12),
//minFontSize: 2,
maxLines: 1,
)
: SizedBox(
width: 20.h,
height: 20.h,
child: CircularProgressIndicator(
child: const CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(Colors.white)),

View File

@ -23,23 +23,23 @@ class AppDrawer extends StatelessWidget {
}),
Divider(),
ExpansionTile(
title: Text("Справочники"),
childrenPadding: EdgeInsets.only(left: 18.0),
title: Text('Справочники'), // ignore: prefer_const_constructors
childrenPadding: const EdgeInsets.only(left: 18.0),
children: <Widget>[
ListTile(
title: Text('Категории'),
title: const Text('Категории'),
onTap: () {
Navigator.of(context).pop();
},
),
ListTile(
title: Text('Товары'),
title: const Text('Товары'),
onTap: () {
Navigator.of(context).pop();
},
),
ListTile(
title: Text('Контрагенты'),
title: const Text('Контрагенты'),
onTap: () {
Navigator.of(context).pop();
},
@ -79,7 +79,7 @@ class AppDrawer extends StatelessWidget {
Positioned(
bottom: 12.0,
left: 16.0,
child: Text("Сату - онлайн касса",
child: Text('Сату - онлайн касса',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,

View File

@ -4,10 +4,21 @@ 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 DropDownField extends StatefulWidget {
const DropDownField(
{required this.placeholder,
this.fieldFocusNode,
this.nextFocusNode,
this.additionalNote,
this.onChanged,
this.initialValue,
this.validationMessage,
this.isReadOnly = false,
this.smallVersion = false,
this.labelText});
final bool isReadOnly;
final String placeholder;
final String? validationMessage;
@ -19,17 +30,7 @@ class DropDownField extends StatefulWidget {
final String? initialValue;
final String? labelText;
DropDownField(
{
required this.placeholder,
this.fieldFocusNode,
this.nextFocusNode,
this.additionalNote,
this.onChanged,
this.initialValue,
this.validationMessage,
this.isReadOnly = false,
this.smallVersion = false, this.labelText});
@override
_DropDownFieldState createState() => _DropDownFieldState();
@ -51,14 +52,16 @@ class _DropDownFieldState extends State<DropDownField> {
if (widget.labelText != null) NoteText(widget.labelText ?? ''),
Container(
//height: widget.smallVersion ? 40 : fieldHeight,
constraints: BoxConstraints(minHeight: widget.smallVersion ? 40 : fieldHeight),
constraints:
BoxConstraints(minHeight: widget.smallVersion ? 40 : fieldHeight),
alignment: Alignment.centerLeft,
padding: fieldPadding,
decoration: widget.isReadOnly ? disabledFieldDecoration : fieldDecoration,
child: Expanded(
child: Container()
decoration:
widget.isReadOnly ? disabledFieldDecoration : fieldDecoration,
child: Expanded(child: Container()
// SearchableDropdown.single(
// items: <String>['Частное лицо', 'ИП Иванов', 'ТО "Рога и копыта"', 'Network Energy']
// items: <String>['Частное лицо', 'ИП Иванов',
// 'ТО "Рога и копыта"', 'Network Energy']
// .map<DropdownMenuItem<String>>((String value) {
// return DropdownMenuItem<String>(
// value: value,
@ -72,7 +75,8 @@ class _DropDownFieldState extends State<DropDownField> {
// underline: Container(
// height: 1.0,
// decoration: BoxDecoration(
// border: Border(bottom: BorderSide(color: yellowColor, width: 3.0))
// border: Border(bottom:
// BorderSide(color: yellowColor, width: 3.0))
// ),
// ),
// onChanged: (value) {
@ -88,7 +92,8 @@ class _DropDownFieldState extends State<DropDownField> {
color: Colors.red,
),
if (widget.additionalNote != null) verticalSpace(5),
if (widget.additionalNote != null) NoteText(widget.additionalNote ?? ''),
if (widget.additionalNote != null)
NoteText(widget.additionalNote ?? ''),
verticalSpaceSmall
],
);

View File

@ -13,7 +13,7 @@ class InputField extends StatefulWidget {
final bool password;
final bool search;
final bool isReadOnly;
final String placeholder;
final String? placeholder;
final String? validationMessage;
final Function? enterPressed;
final bool smallVersion;
@ -26,16 +26,17 @@ class InputField extends StatefulWidget {
final TextInputFormatter? formatter;
final String? initialValue;
final String? labelText;
final String? suffixText;
InputField(
{
required this.controller,
required this.placeholder,
{required this.controller,
this.placeholder,
this.enterPressed,
this.fieldFocusNode,
this.nextFocusNode,
this.additionalNote,
this.onChanged,
this.suffixText,
this.formatter,
this.initialValue,
this.validationMessage,
@ -45,7 +46,8 @@ class InputField extends StatefulWidget {
this.search = false,
this.isReadOnly = false,
this.multiline = false,
this.smallVersion = false, this.labelText});
this.smallVersion = false,
this.labelText});
@override
_InputFieldState createState() => _InputFieldState();
@ -77,10 +79,16 @@ class _InputFieldState extends State<InputField> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (widget.labelText != null) NoteText(widget.labelText ?? ''),
if (widget.labelText != null)
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 14.0, vertical: 5.0),
child: NoteText(widget.labelText ?? ''),
),
Container(
//height: widget.smallVersion ? 40 : fieldHeight,
constraints: BoxConstraints(minHeight: widget.smallVersion ? 40.h : fieldHeight),
constraints: BoxConstraints(
minHeight: widget.smallVersion ? 40.h : fieldHeight),
alignment: Alignment.centerLeft,
padding: fieldPadding,
decoration:
@ -95,24 +103,28 @@ class _InputFieldState extends State<InputField> {
setState(() {
isSearch = !isSearch;
});
FocusScope.of(context).requestFocus(new FocusNode()); //remove focus
WidgetsBinding.instance!.addPostFrameCallback((_) => widget.controller.clear()); // clear content
FocusScope.of(context)
.requestFocus(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))
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) ),
style: TextStyle(
color: textColor,
fontSize: widget.smallVersion
? 12
: 14),
controller: widget.controller,
keyboardType: widget.textInputType,
focusNode: widget.fieldFocusNode,
@ -138,10 +150,15 @@ class _InputFieldState extends State<InputField> {
decoration: InputDecoration(
hintText: widget.placeholder,
filled: true,
suffixText: widget.suffixText,
suffixStyle: const TextStyle(color: textColor),
fillColor: whiteColor,
border: InputBorder.none,
hintStyle:
TextStyle(fontSize: widget.smallVersion ? ScreenUtil().setSp(12) : ScreenUtil().setSp(15), color: placeholderColor)),
hintStyle: TextStyle(
fontSize: widget.smallVersion
? ScreenUtil().setSp(12)
: ScreenUtil().setSp(14),
color: placeholderColor)),
),
),
GestureDetector(
@ -153,9 +170,11 @@ class _InputFieldState extends State<InputField> {
width: fieldHeight,
height: fieldHeight,
alignment: Alignment.center,
child: Icon(isPassword
child: Icon(
isPassword
? Icons.visibility
: Icons.visibility_off, color: textColor))
: Icons.visibility_off,
color: textColor))
: Container(),
),
],
@ -167,7 +186,8 @@ class _InputFieldState extends State<InputField> {
color: dangerColor,
),
if (widget.additionalNote != null) verticalSpace(5),
if (widget.additionalNote != null) NoteText(widget.additionalNote ?? ''),
if (widget.additionalNote != null)
NoteText(widget.additionalNote ?? ''),
verticalSpaceSmall
],
);

View File

@ -124,8 +124,8 @@ class _InputFieldRoundedState extends State<InputFieldRounded> {
style: TextStyle(
color: textColor,
fontSize: widget.smallVersion
? ScreenUtil().setSp(12)
: ScreenUtil().setSp(15)),
? 12
: 14),
controller: widget.controller,
keyboardType: widget.textInputType,
focusNode: widget.fieldFocusNode,

View File

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class LineCheckBox extends StatelessWidget {
const LineCheckBox(this.text, { required this.value });
final String text;
final bool value;
@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
color: whiteColor
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 12.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
text,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.normal,
),
),
SizedBox(
width: 20.w,
child: Visibility(
visible: value,
child: const Icon(
Icons.check,
color: primaryColor,
),
),
)
],
),
),
),
),
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class NoteText extends StatelessWidget {
const NoteText(this.text, {this.textAlign, this.color, this.fontSize});

View File

@ -85,7 +85,7 @@ class _BarcodePermissionWidgetState extends State<_BarcodePermissionWidget> {
onPressed: () {
_requestMobilePermission();
},
child: Text("Запроса на разрешения"),
child: const Text('Запроса на разрешения'),
),
),
),

View File

@ -20,7 +20,10 @@ class LogoSatu extends StatelessWidget {
height: 75.h,
child: Image.asset('assets/images/logo.png'),
),
AutoSizeText('Товароучетная система', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w400 ), )
AutoSizeText(
'Товароучетная система',
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w400),
)
],
),
),

View File

@ -5,7 +5,9 @@ import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/views/work/tabs/component/product_list_item.dart';
class ProductTitleWidget extends StatelessWidget {
const ProductTitleWidget({Key? key, required this.name, this.ean, this.categoryName}) : super(key: key);
const ProductTitleWidget(
{required this.name, Key? key, this.ean, this.categoryName})
: super(key: key);
final String name;
final String? ean;