dictionaries

null-safety-migration
suvaysov 2022-06-28 16:13:59 +06:00
parent 44a6de4f58
commit 34b669eea0
86 changed files with 1466 additions and 949 deletions

View File

@ -1,19 +1,16 @@
# satu
Aman Satu App
## Getting Started
This project is a starting point for a Flutter application.
# build_runner
flutter pub run build_runner build --delete-conflicting-outputs
flutter pub run build_runner watch --delete-conflicting-outputs
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
# build android apk
flutter build --release apk --flavor production
# build android appbundle
flutter build --release appbundle --flavor production
## Сборка релизного пакет
flutter clean && flutter build appbundle --release

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -3,13 +3,13 @@ import 'package:logger/logger.dart';
import '../utils/logger.dart';
class BaseService {
Logger log = getLogger(
'BaseService',
);
BaseService({String? title}) {
this.log = getLogger(
title ?? this.runtimeType.toString(),
);
}
Logger log = getLogger(
'BaseService',
);
}

View File

@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
class DialogRequest {
DialogRequest(

View File

@ -9,11 +9,10 @@ class CategoryResponse {
String name = '';
String? updatedAt;
static CategoryResponse? fromMap(dynamic map) {
if (map == null) return null;
static CategoryResponse fromMap(dynamic map) {
final CategoryResponse categoryResponseBean = CategoryResponse();
categoryResponseBean.id = map['id'] as int;
categoryResponseBean.parentId = map['parent_id'] as int;
categoryResponseBean.parentId = map['parent_id'] as int?;
categoryResponseBean.name = map['name'] as String;
categoryResponseBean.updatedAt = map['updated_at'] as String;
return categoryResponseBean;

View File

@ -0,0 +1,29 @@
import 'package:json_annotation/json_annotation.dart';
import 'dart:convert';
part 'contragent_response_entity.g.dart';
@JsonSerializable()
class ContragentResponseEntity {
factory ContragentResponseEntity.fromJson(Map<String, dynamic> json) =>
_$ContragentResponseEntityFromJson(json);
ContragentResponseEntity();
int? id;
String? biniin;
@JsonKey(name: 'ref_app_company_type_id')
late int refAppCompanyTypeId;
String? name;
String? phone;
String? email;
int? nds;
int? resident;
Map<String, dynamic> toJson() => _$ContragentResponseEntityToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}

View File

@ -0,0 +1,32 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'contragent_response_entity.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ContragentResponseEntity _$ContragentResponseEntityFromJson(
Map<String, dynamic> json) =>
ContragentResponseEntity()
..id = json['id'] as int?
..biniin = json['biniin'] as String?
..refAppCompanyTypeId = json['ref_app_company_type_id'] as int
..name = json['name'] as String?
..phone = json['phone'] as String?
..email = json['email'] as String?
..nds = json['nds'] as int?
..resident = json['resident'] as int?;
Map<String, dynamic> _$ContragentResponseEntityToJson(
ContragentResponseEntity instance) =>
<String, dynamic>{
'id': instance.id,
'biniin': instance.biniin,
'ref_app_company_type_id': instance.refAppCompanyTypeId,
'name': instance.name,
'phone': instance.phone,
'email': instance.email,
'nds': instance.nds,
'resident': instance.resident,
};

View File

@ -22,19 +22,22 @@ class GoodResponse {
double? basePrice;
int? divisible;
String? updatedAt;
String? categoryName;
static GoodResponse fromMap(dynamic map) {
final GoodResponse goodResponseBean = GoodResponse();
goodResponseBean.id = map['id'] as int;
goodResponseBean.categoryId = map['category_id'] as int;
goodResponseBean.categoryId = map['eacc_good_category_id'] as int?;
goodResponseBean.name = map['name'] as String;
goodResponseBean.ean = map['ean'] as String;
goodResponseBean.ean = map['ean'] as String?;
goodResponseBean.articul = map['articul'] as int;
goodResponseBean.price = (cast<num>(map['price']) ?? 0).toDouble() ;
goodResponseBean.optPrice = (cast<num>(map['opt_price']) ?? 0).toDouble();
goodResponseBean.basePrice = (cast<num>(map['base_price']) ?? 0).toDouble();
goodResponseBean.divisible = map['divisible'] as int;
goodResponseBean.divisible = map['divisible'] as int?;
goodResponseBean.updatedAt = map['updated_at'] as String;
goodResponseBean.categoryName = map['category_name'] as String?;
return goodResponseBean;
}

View File

@ -0,0 +1,62 @@
import 'package:json_annotation/json_annotation.dart';
import 'dart:convert';
part 'dict_response_entity.g.dart';
@JsonSerializable()
class DictResponseEntity {
factory DictResponseEntity.fromJson(Map<String, dynamic> json) => _$DictResponseEntityFromJson(json);
DictResponseEntity();
late DictResponseHeaders headers;
late DictResponseOriginal original;
String? exception;
Map<String, dynamic> toJson() => _$DictResponseEntityToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}
@JsonSerializable()
class DictResponseHeaders {
DictResponseHeaders();
factory DictResponseHeaders.fromJson(Map<String, dynamic> json) => _$DictResponseHeadersFromJson(json);
Map<String, dynamic> toJson() => _$DictResponseHeadersToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}
@JsonSerializable()
class DictResponseOriginal {
factory DictResponseOriginal.fromJson(Map<String, dynamic> json) => _$DictResponseOriginalFromJson(json);
DictResponseOriginal();
int? overall;
int? page;
int? perpage;
List<dynamic>? data;
Map<String, List<String>>? errors;
String? message;
Map<String, dynamic> toJson() => _$DictResponseOriginalToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}

View File

@ -0,0 +1,53 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'dict_response_entity.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DictResponseEntity _$DictResponseEntityFromJson(Map<String, dynamic> json) =>
DictResponseEntity()
..headers =
DictResponseHeaders.fromJson(json['headers'] as Map<String, dynamic>)
..original = DictResponseOriginal.fromJson(
json['original'] as Map<String, dynamic>)
..exception = json['exception'] as String?;
Map<String, dynamic> _$DictResponseEntityToJson(DictResponseEntity instance) =>
<String, dynamic>{
'headers': instance.headers,
'original': instance.original,
'exception': instance.exception,
};
DictResponseHeaders _$DictResponseHeadersFromJson(Map<String, dynamic> json) =>
DictResponseHeaders();
Map<String, dynamic> _$DictResponseHeadersToJson(
DictResponseHeaders instance) =>
<String, dynamic>{};
DictResponseOriginal _$DictResponseOriginalFromJson(
Map<String, dynamic> json) =>
DictResponseOriginal()
..overall = json['overall'] as int?
..page = json['page'] as int?
..perpage = json['perpage'] as int?
..data = json['data'] as List<dynamic>?
..errors = (json['errors'] as Map<String, dynamic>?)?.map(
(k, e) =>
MapEntry(k, (e as List<dynamic>).map((e) => e as String).toList()),
)
..message = json['message'] as String?;
Map<String, dynamic> _$DictResponseOriginalToJson(
DictResponseOriginal instance) =>
<String, dynamic>{
'overall': instance.overall,
'page': instance.page,
'perpage': instance.perpage,
'data': instance.data,
'errors': instance.errors,
'message': instance.message,
};

View File

@ -1,4 +1,3 @@
import 'package:satu/core/utils/utils_parse.dart';
class TransactionDao {
TransactionDao();

View File

@ -4,13 +4,13 @@ part 'sell_return_request.g.dart';
@JsonSerializable()
class SellReturnRequest {
int journal_id;
String invoice_id;
factory SellReturnRequest.fromJson(Map<String, dynamic> json) =>
_$SellReturnRequestFromJson(json);
SellReturnRequest({required this.journal_id, required this.invoice_id});
factory SellReturnRequest.fromJson(Map<String, dynamic> json) => _$SellReturnRequestFromJson(json);
int journal_id;
String invoice_id;
Map<String, dynamic> toJson() => _$SellReturnRequestToJson(this);
}

View File

@ -6,12 +6,11 @@ part of 'sell_return_request.dart';
// JsonSerializableGenerator
// **************************************************************************
SellReturnRequest _$SellReturnRequestFromJson(Map<String, dynamic> json) {
return SellReturnRequest(
journal_id: json['journal_id'] as int,
invoice_id: json['invoice_id'] as String,
);
}
SellReturnRequest _$SellReturnRequestFromJson(Map<String, dynamic> json) =>
SellReturnRequest(
journal_id: json['journal_id'] as int,
invoice_id: json['invoice_id'] as String,
);
Map<String, dynamic> _$SellReturnRequestToJson(SellReturnRequest instance) =>
<String, dynamic>{

View File

@ -1,34 +0,0 @@
import 'package:satu/core/utils/utils_parse.dart';
/// list : []
/// message : ""
/// operation : true
class Response {
List? list;
String? message;
bool? operation;
Response();
factory Response.fromMapList(dynamic map, Function(dynamic)? parser) {
final List list = [];
if (map['list'] != null) {
(map['list'] as List).forEach((dynamic element) {
if(parser == null) {
list.add(element);
} else {
list.add(parser(element));
}
});
}
final Response responseBean = Response();
responseBean.list = list;
responseBean.message = cast<String>(map['message']);
responseBean.operation = map['operation'] as bool;
return responseBean;
}
}

View File

@ -12,6 +12,14 @@ class PrinterConst {
class PrinterSetting {
factory PrinterSetting.fromMap(dynamic map) {
return PrinterSetting(
device: map['device']!=null ? PrinterDevice.fromMap(map['device']) : null,
encoding: cast<String>(map['encoding']),
paperSize: cast<String>(map['paperSize']),
);
}
PrinterSetting({
this.device,
this.encoding = PrinterConst.encodingCP866,
@ -30,37 +38,9 @@ class PrinterSetting {
};
}
factory PrinterSetting.fromMap(dynamic map) {
return PrinterSetting(
device: map['device']!=null ? PrinterDevice.fromMap(map['device']) : null,
encoding: cast<String>(map['encoding']),
paperSize: cast<String>(map['paperSize']),
);
}
}
class PrinterDevice {
String? name;
String? address;
int? type = 0;
bool? connected = false;
PrinterDevice({
this.name,
this.address,
this.type,
this.connected,
});
dynamic toMap() {
return {
'name': name,
'address': address,
'type': type,
'connected': connected,
};
}
factory PrinterDevice.fromMap(dynamic map) {
return PrinterDevice(
@ -70,4 +50,24 @@ class PrinterDevice {
connected: cast<bool>(map['connected']),
);
}
PrinterDevice({
this.name,
this.address,
this.type,
this.connected,
});
String? name;
String? address;
int? type = 0;
bool? connected = false;
dynamic toMap() {
return {
'name': name,
'address': address,
'type': type,
'connected': connected,
};
}
}

View File

@ -1,4 +1,3 @@
import 'package:satu/core/utils/utils_parse.dart';
class PopupItemDao {
PopupItemDao({required this.code, required this.name});

View File

@ -5,20 +5,13 @@ import 'package:logger/logger.dart';
import 'package:meta/meta.dart';
import 'package:redux/redux.dart';
import 'package:redux_thunk/redux_thunk.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/entity/transaction_entity.dart';
import 'package:satu/core/entity/transaction_rec_entity.dart';
import 'package:satu/core/models/entity_data/transaction_data.dart';
import 'package:satu/core/models/flow/dao/product_dao.dart';
import 'package:satu/core/models/flow/dao/transaction_dao.dart';
import 'package:satu/core/models/flow/transaction_state.dart';
import 'package:satu/core/redux/state/journal_state.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/services/db_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/core/utils/logger.dart';
import 'package:uuid/uuid.dart';
import '../store.dart';
@ -44,7 +37,6 @@ Future<void> loadJournalData(Store<AppState> store) async {
try {
log.i('loadJournalData');
final int? appCompanyId = store.state.userState!.auth!.companyId;
final int tabIndex = store.state.journalState?.tabIndex ?? 0;
final List<Map<String, dynamic>> set = await _dbService.queryRowsWithWhere(
transactionTableName,
'$transactionColumnAppCompanyId = ?'
@ -75,7 +67,7 @@ Future<void> loadJournalData(Store<AppState> store) async {
dao.contragentName = data.contragentName;
dao.number = data.sellResponse?.journalId.toString() ?? '';
dao.total = data.total;
if(transaction.type == transactionTypeReturnSell) {
if (transaction.type == transactionTypeReturnSell) {
dao.received = false;
}

View File

@ -8,8 +8,8 @@ import '../store.dart';
@immutable
class SetNavStateAction {
final NavState navState;
SetNavStateAction(this.navState);
final NavState navState;
}
ThunkAction<AppState> navigateDrawer(Type viewClass) {

View File

@ -1,26 +1,11 @@
import 'dart:convert';
import 'package:intl/intl.dart';
import 'package:logger/logger.dart';
import 'package:meta/meta.dart';
import 'package:redux/redux.dart';
import 'package:redux_thunk/redux_thunk.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/entity/transaction_entity.dart';
import 'package:satu/core/entity/transaction_rec_entity.dart';
import 'package:satu/core/models/entity_data/transaction_data.dart';
import 'package:satu/core/models/flow/dao/product_dao.dart';
import 'package:satu/core/models/flow/dao/transaction_dao.dart';
import 'package:satu/core/models/flow/transaction_state.dart';
import 'package:satu/core/models/settings/printer_setting.dart';
import 'package:satu/core/redux/state/journal_state.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/state/setting_state.dart';
import 'package:satu/core/services/db_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/core/utils/logger.dart';
import 'package:uuid/uuid.dart';
import '../store.dart';

View File

@ -13,9 +13,9 @@ import '../store.dart';
@immutable
class SetUserStateAction {
final UserState userState;
SetUserStateAction(this.userState);
final UserState userState;
}
final ApiService _api = locator<ApiService>();

View File

@ -1,9 +1,5 @@
import 'package:satu/core/redux/actions/journal_actions.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/actions/user_actions.dart';
import 'package:satu/core/redux/state/journal_state.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/state/user_state.dart';
JournalState journalReducer(
JournalState prevState, SetJournalStateAction action) {

View File

@ -1,7 +1,5 @@
import 'package:satu/core/redux/actions/nav_actions.dart';
import 'package:satu/core/redux/actions/user_actions.dart';
import 'package:satu/core/redux/state/nav_state.dart';
import 'package:satu/core/redux/state/user_state.dart';
NavState navReducer(NavState prevState, SetNavStateAction action) {
final NavState payload = action.navState;

View File

@ -1,7 +1,5 @@
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/actions/user_actions.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/state/user_state.dart';
SellState sellReducer(SellState prevState, SetSellStateAction action) {
final SellState payload = action.sellState;

View File

@ -1,11 +1,5 @@
import 'package:satu/core/redux/actions/journal_actions.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/actions/setting_actions.dart';
import 'package:satu/core/redux/actions/user_actions.dart';
import 'package:satu/core/redux/state/journal_state.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/state/setting_state.dart';
import 'package:satu/core/redux/state/user_state.dart';
SettingState settingReducer(
SettingState prevState, SetSettingStateAction action) {

View File

@ -3,8 +3,6 @@ import 'package:satu/views/work/work_view.dart';
@immutable
class NavState {
final Type? drawerViewClass;
final int? selectedTabIndex;
NavState({this.drawerViewClass, this.selectedTabIndex});
@ -12,6 +10,8 @@ class NavState {
drawerViewClass: WorkView,
selectedTabIndex: 0,
);
final Type? drawerViewClass;
final int? selectedTabIndex;
NavState copyWith({
required int? selectedTabIndex,

View File

@ -1,23 +1,24 @@
import 'package:meta/meta.dart';
import 'package:satu/core/models/auth/auth_response.dart';
import 'package:satu/core/models/flow/dao/product_dao.dart';
import 'package:satu/core/models/flow/transaction_state.dart';
@immutable
class SellState {
final List<ProductDao>? items;
final TransactionState? transactionState;
SellState({this.items, this.transactionState});
factory SellState.initial() => SellState(
items: [],
transactionState: TransactionState(),
);
SellState copyWith({required List<ProductDao>? items, required TransactionState? transactionState}) {
return SellState(items: items ?? this.items, transactionState: transactionState ?? this.transactionState);
SellState({this.items, this.transactionState});
final List<ProductDao>? items;
final TransactionState? transactionState;
SellState copyWith(
{required List<ProductDao>? items,
required TransactionState? transactionState}) {
return SellState(
items: items ?? this.items,
transactionState: transactionState ?? this.transactionState);
}
}

View File

@ -1,9 +1,17 @@
import 'package:meta/meta.dart';
import 'package:satu/core/models/flow/dao/transaction_dao.dart';
import 'package:satu/core/models/settings/printer_setting.dart';
@immutable
class SettingState {
factory SettingState.fromMap(dynamic map) {
if (map == null) return SettingState.initial(null);
return SettingState(
printer: map['printer'] != null
? PrinterSetting.fromMap(map['printer'])
: null,
);
}
const SettingState({this.printer});
factory SettingState.initial(SettingState? settingState) =>
@ -20,13 +28,4 @@ class SettingState {
'printer': printer !=null ? printer!.toMap() : null,
};
}
factory SettingState.fromMap(dynamic map) {
if (map == null) return SettingState.initial(null);
return SettingState(
printer: map['printer'] != null
? PrinterSetting.fromMap(map['printer'])
: null,
);
}
}

View File

@ -5,9 +5,12 @@ import 'package:satu/core/models/auth/auth_response.dart';
@immutable
class UserState {
final bool? isError;
final bool? isLoading;
final AuthResponse? auth;
factory UserState.initial(UserState? payload) => UserState(
isLoading: false,
isError: false,
auth: payload?.auth ?? (AuthResponse()..operation=false),
);
UserState(
@ -15,12 +18,9 @@ class UserState {
this.isLoading,
this.auth,
});
factory UserState.initial(UserState? payload) => UserState(
isLoading: false,
isError: false,
auth: payload?.auth ?? (AuthResponse()..operation=false),
);
final bool? isError;
final bool? isLoading;
final AuthResponse? auth;
UserState copyWith({
required bool? isError,

View File

@ -120,7 +120,8 @@ class Redux {
final navStateInitial = NavState.initial();
final sellStateInitial = SellState.initial();
final journalStateInitial = JournalState.initial();
final settingStateInitial = SettingState.initial(initialState?.settingState);
final settingStateInitial =
SettingState.initial(initialState?.settingState);
_store = Store<AppState>(
appReducer,

View File

@ -4,18 +4,18 @@ import 'dart:io';
import 'package:satu/core/base/base_service.dart';
import 'package:http/http.dart' as http;
import 'package:satu/core/models/auth/auth_response.dart';
import 'package:satu/core/models/dictionary/response/dict_response_entity.dart';
import 'package:satu/core/models/flow/analytics/analytics_bean.dart';
import 'package:satu/core/models/flow/sell_request.dart';
import 'package:satu/core/models/flow/sell_response.dart';
import 'package:satu/core/models/flow/sell_return/sell_return_request.dart';
import 'package:satu/core/models/response.dart';
/// The service responsible for networking requests
class ApiService extends BaseService {
static const host = 'satu.aman.com.kz';
static const endpoint = '/api/v1';
http.Client client = http.Client();
//TOKEN
String? token;
@ -38,15 +38,18 @@ class ApiService extends BaseService {
{Map<String, dynamic>? requestBody, Map<String, String>? header}) async {
final Map<String, String> headers = <String, String>{
HttpHeaders.contentTypeHeader: 'application/json',
HttpHeaders.cacheControlHeader: 'no-cache'
HttpHeaders.cacheControlHeader: 'no-cache',
};
if (header != null && header.isNotEmpty) {
headers.addAll(header);
}
final String url = '$endpoint$point';
if (requestBody != null) {
log.i(jsonEncode(requestBody));
}
// if (requestBody != null) {
// log.i(host);
// log.i(url);
// log.i(headers);
// log.i(jsonEncode(requestBody));
// }
final response = await http.post(Uri.https(host, url),
body: jsonEncode(requestBody), headers: headers);
@ -121,36 +124,55 @@ class ApiService extends BaseService {
return result;
}
Future<Response> dictionaries(String target) async {
Response result;
Future<DictResponseEntity> dictionaries(String target,
{Map<String, dynamic>? requestBody}) async {
DictResponseEntity result;
try {
final Map<String, String> headers = <String, String>{
HttpHeaders.authorizationHeader: 'Bearer $token'
};
final String response = await _post(target, header: headers);
result = Response.fromMapList(json.decode(response), null);
final String response =
await _post(target, header: headers, requestBody: requestBody);
result = DictResponseEntity.fromJson(json.decode(response));
} catch (e, stack) {
log.e('dictionaries', e, stack);
result = Response()
..operation = false
..list = [];
result = DictResponseEntity()..exception = e.toString();
}
return result;
}
Future<DictResponseEntity> dictionarySave(
String target, Map<String, dynamic>? body) async {
DictResponseEntity response;
try {
final Map<String, String> headers = <String, String>{
HttpHeaders.authorizationHeader: 'Bearer $token'
};
final String responseBody =
await _post(target, header: headers, requestBody: body);
response = DictResponseEntity.fromJson(json.decode(responseBody));
} catch (e, stack) {
log.e('dictionarySave', e, stack);
response = DictResponseEntity()..exception = e.toString();
}
return response;
}
Future<SellResponse> sell(SellRequest request) async {
SellResponse response;
try {
final Map<String, String> headers = <String, String>{
HttpHeaders.authorizationHeader: 'Bearer $token'
};
final String responseBody = await _post('/sell', header: headers, requestBody: request.toJson());
final String responseBody =
await _post('/sell', header: headers, requestBody: request.toJson());
response = SellResponse.fromMap(json.decode(responseBody));
} catch (e, stack) {
log.e('dictionaries', e, stack);
response = SellResponse()
..operation = false
..message = e.toString();
..message = e.toString();
}
return response;
}
@ -161,7 +183,8 @@ class ApiService extends BaseService {
final Map<String, String> headers = <String, String>{
HttpHeaders.authorizationHeader: 'Bearer $token'
};
final String responseBody = await _post('/sell_return', header: headers, requestBody: request.toJson());
final String responseBody = await _post('/sell_return',
header: headers, requestBody: request.toJson());
response = SellResponse.fromMap(json.decode(responseBody));
} catch (e, stack) {
log.e('sellReturn', e, stack);
@ -179,7 +202,6 @@ class ApiService extends BaseService {
HttpHeaders.authorizationHeader: 'Bearer $token'
};
final String responseBody = await _get('/get_analytics', header: headers);
log.i(responseBody);
response = AnalyticsBean.fromMap(json.decode(responseBody));
} catch (e, stack) {
log.e('getAnalytics', e, stack);

View File

@ -1,6 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:satu/core/base/base_service.dart';
import 'package:satu/core/entity/transaction_entity.dart';
import 'package:satu/core/models/entity_data/transaction_data.dart';
@ -160,7 +159,6 @@ class DataService extends BaseService {
transaction.data = jsonEncode(data.toMap());
log.i(jsonEncode(data.toMap()));
return await _db.insert(transactionTableName, transaction.toMap());
;
}
ItemBean _productToItemBean(ProductDao product) {

View File

@ -10,11 +10,11 @@ import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
class DbService extends BaseService {
static const _databaseName = 'AmanSatuDb.db';
static const _databaseVersion = 2;
// make this a singleton class
DbService._privateConstructor();
static const _databaseName = 'AmanSatuDb.db';
static const _databaseVersion = 2;
static final DbService instance = DbService._privateConstructor();

View File

@ -21,7 +21,8 @@ class DialogService {
_showDialogInputListener = showDialogInputListener;
}
/// Calls the dialog listener and returns a Future that will wait for dialogComplete.
/// Calls the dialog listener
/// and returns a Future that will wait for dialogComplete.
Future<DialogResponse> showDialog({
String title = 'SATU',
String? description,

View File

@ -2,8 +2,9 @@ import 'package:satu/core/base/base_service.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/models/dictionary/category_response.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/core/models/dictionary/good_response.dart';
import 'package:satu/core/models/response.dart';
import 'package:satu/core/models/dictionary/response/dict_response_entity.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/utils/locator.dart';
@ -15,32 +16,10 @@ class DictionaryService extends BaseService {
final DbService _db = locator<DbService>();
Future<void> refreshFull() async {
_db.deleteAll(categoryTableName);
await refreshCategory();
_db.deleteAll(goodTableName);
await refreshGood();
}
Future<void> refreshCategory() async {
try {
final int? appCompanyId = Redux.store!.state.userState!.auth!.companyId;
final Response categories = await _api.dictionaries('/categories');
if (categories.operation! && categories.list!.isNotEmpty) {
for (dynamic map in categories.list!) {
CategoryResponse cat = CategoryResponse.fromMap(map)!;
Category entity = new Category()
..id = cat.id
..name = cat.name
..updatedAt = cat.updatedAt
..parentId = cat.parentId
..appCompanyId = appCompanyId;
_db.insert(categoryTableName, entity.toMap());
}
}
} catch (e, stack) {
log.e('categories', e, stack);
}
}
Future<List<Category>> getCategoryByParentId(int parentId) async {
final List<Category> list = [];
@ -77,23 +56,7 @@ class DictionaryService extends BaseService {
return result;
}
Future<List<Category>> getCategoriesAll() async {
final List<Category> list = [];
try {
final int? appCompanyId = Redux.store?.state.userState?.auth?.companyId;
final List<Map<String, dynamic>> elements = await _db.queryRowsWithWhere(
categoryTableName,
'$categoryColumnAppCompanyId = ? '
' order by $categoryColumnParentIn asc, $categoryColumnId asc ',
[appCompanyId]);
for (final Map<String, dynamic> element in elements) {
list.add(Category.fromMap(element));
}
} catch (e, stack) {
log.e('getCategoriesAll', e, stack);
}
return list;
}
Future<List<Good>> getGoodsByCategoryId(int categoryId) async {
final List<Good> list = [];
@ -134,55 +97,126 @@ class DictionaryService extends BaseService {
return list;
}
Future<List<Good>> getGoodsByEan(String code) async {
final List<Good> list = [];
try {
final int? appCompanyId = Redux.store?.state.userState?.auth?.companyId;
final String where =
'( $GoodColumnAppCompanyId = ? and $GoodColumnEan like ? ) ';
final List args = [appCompanyId, '%$code%'];
final List<Map<String, dynamic>> elements =
await _db.queryRowsWithWhere(goodTableName, where, args);
for (final Map<String, dynamic> element in elements) {
list.add(Good.fromMap(element));
}
} catch (e, stack) {
log.e('getGoodsByEan', e, stack);
}
return list;
}
bool _isNumericInt(String str) {
bool _isNumericInt(String? str) {
if (str == null) {
return false;
}
return int.tryParse(str) != null;
}
Future<void> refreshGood() async {
Future<List<CategoryResponse>> getCategories( {required int page, String? query, required int perpage}) async {
List<CategoryResponse> list = [];
try {
int? appCompanyId = Redux.store!.state.userState!.auth!.companyId;
Response categories = await _api.dictionaries('/goods');
if (categories.operation! && categories.list!.isNotEmpty) {
for (final dynamic map in categories.list!) {
final GoodResponse good = GoodResponse.fromMap(map);
final Good entity = new Good()
..id = good.id
..name = good.name
..categoryId = good.categoryId
..ean = good.ean
..articul = good.articul
..price = good.price
..optPrice = good.optPrice
..basePrice = good.basePrice
..divisible = good.divisible
..updatedAt = good.updatedAt
..appCompanyId = appCompanyId;
_db.insert(goodTableName, entity.toMap());
final Map<String, dynamic> requestBody = <String, dynamic>{
'page': page,
'perpage': perpage,
'filter': [
{'col': 'name', 'action': 'like', 'val': query ?? ''}
]
};
DictResponseEntity categories =
await _api.dictionaries('/goods_categories_get', requestBody: requestBody);
if (categories.original.data != null &&
categories.original.data!.isNotEmpty) {
for (final dynamic map in categories.original.data!) {
final CategoryResponse good = CategoryResponse.fromMap(map);
list.add(good);
}
}
} catch (e, stack) {
log.e('goods', e, stack);
log.e('getCategories', e, stack);
}
return list;
}
Future<List<GoodResponse>> getGoods(
{required int page, String? query, required int perpage}) async {
List<GoodResponse> list = [];
try {
final Map<String, dynamic> requestBody = <String, dynamic>{
'page': page,
'perpage': perpage,
'filter': [
{'col': 'name', 'action': 'like', 'val': query ?? ''}
]
};
DictResponseEntity categories =
await _api.dictionaries('/goods_goods_get', requestBody: requestBody);
if (categories.original.data != null &&
categories.original.data!.isNotEmpty) {
for (final dynamic map in categories.original.data!) {
final GoodResponse good = GoodResponse.fromMap(map);
list.add(good);
}
}
} catch (e, stack) {
log.e('getGoods', e, stack);
}
return list;
}
Future<List<ContragentResponseEntity>> getContragents(
{int? page, int? perpage, String? query}) async {
final List<ContragentResponseEntity> list = [];
try {
final Map<String, dynamic> requestBody = <String, dynamic>{
'page': page,
'perpage': perpage,
'filter': [
{'col': 'name', 'action': 'like', 'val': query ?? ''}
]
};
final DictResponseEntity contragents = await _api
.dictionaries('/general_contragents_get', requestBody: requestBody);
if (contragents.original.data != null) {
if (contragents.original.data!.isNotEmpty) {
for (dynamic map in contragents.original.data!) {
list.add(ContragentResponseEntity.fromJson(map));
}
}
}
} catch (e, stack) {
log.e('getContragents', e, stack);
}
return list;
}
Future<String?> saveContragent(ContragentResponseEntity contragent) async {
DictResponseEntity? status;
if (contragent.id != null) {
status = await _api.dictionarySave(
'/general_contragents_edit', contragent.toJson());
} else {
status = await _api.dictionarySave(
'/general_contragents_add', contragent.toJson());
}
String? message = getErrorMsg(status);
return message;
}
Future<String?> deleteContragent(ContragentResponseEntity contragent) async {
DictResponseEntity status = await _api.dictionarySave(
'/general_contragents_delete', contragent.toJson());
String? message = getErrorMsg(status);
return message;
}
String? getErrorMsg(DictResponseEntity status) {
String? message;
if (status.exception != null) {
message = status.exception;
} else if (status.original.message != null) {
message = status.original.message;
} else if (status.original.errors != null) {
Map<String, List<String>> errors = status.original.errors!;
errors.values.forEach((element) {
message = '${message ?? ''} \n ${element.join(',')}';
});
}
return message;
}
}

View File

@ -14,11 +14,11 @@ class NavigatorService extends BaseService {
Future<dynamic> replace(String routeName, {dynamic arguments}) {
log.d('routeName: $routeName');
return navigatorKey.currentState!
.pushNamedAndRemoveUntil(routeName, (Route<dynamic> route) => false, arguments: arguments);
return navigatorKey.currentState!.pushNamedAndRemoveUntil(
routeName, (Route<dynamic> route) => false,
arguments: arguments);
}
Future<T?> navigateToPage<T>(MaterialPageRoute<T> pageRoute) async {
log.d('navigateToPage: pageRoute: ${pageRoute.settings.name}');
if (navigatorKey.currentState == null) {
@ -31,7 +31,7 @@ class NavigatorService extends BaseService {
Future<T?> navigateToPageWithReplacement<T>(
MaterialPageRoute<T> pageRoute) async {
log.d('navigateToPageWithReplacement: '
'pageRoute: ${pageRoute.settings.name}');
'pageRoute: ${pageRoute.settings.name}');
if (navigatorKey.currentState == null) {
log.e('navigateToPageWithReplacement: Navigator State is null');
return null;
@ -47,4 +47,4 @@ class NavigatorService extends BaseService {
}
navigatorKey.currentState!.pop(result);
}
}
}

View File

@ -2,10 +2,10 @@ import 'dart:convert';
import 'package:logger/logger.dart';
class SimpleLogPrinter extends LogPrinter {
SimpleLogPrinter(this.className);
final String className;
static final _deviceStackTraceRegex = RegExp(r'#[0-9]+[\s]+(.+) \(([^\s]+)\)');
static final _webStackTraceRegex = RegExp(r'^((packages|dart-sdk)\/[^\s]+\/)');
SimpleLogPrinter(this.className);
@override
List<String> log(LogEvent event) {

View File

@ -10,8 +10,6 @@ const String addByBarcodeViewRoute = 'AddByBarcodeView';
const String paymentViewRoute = 'paymentViewRoute';
const String receiptViewRoute = 'receiptViewRoute';
// dictionaries - category
const String categoryEditRoute = 'categoryEditRoute';
const String categorySelectViewRoute = 'categorySelectViewRoute';
@ -20,10 +18,13 @@ const String goodsEditRoute = 'goodsEditRoute';
const String goodsDictionaryViewRoute = 'goodsDictionaryViewRoute';
//dictionaries - contragent
const String contragentSelectViewRoute = 'ContragentSelectViewRoute';
const String contragentEditRoute = 'contragentEditRoute';
// setting - ble printer
const String settingPrinterBluetoothViewRoute = 'SettingPrinterBluetoothView';
const String settingPrinterBluetoothSelectViewRoute = 'settingPrinterBluetoothSelectViewRoute';
const String settingPrinterPaperSizeViewRoute = 'settingPrinterPaperSizeViewRoute';
const String settingPrinterEncodingViewRoute = 'settingPrinterEncodingViewRoute';
const String settingPrinterBluetoothSelectViewRoute =
'settingPrinterBluetoothSelectViewRoute';
const String settingPrinterPaperSizeViewRoute =
'settingPrinterPaperSizeViewRoute';
const String settingPrinterEncodingViewRoute =
'settingPrinterEncodingViewRoute';

View File

@ -1,9 +1,12 @@
import 'package:flutter/material.dart';
import 'package:satu/core/models/dictionary/category_response.dart';
import 'package:satu/core/models/dictionary/category_row_data.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/core/models/dictionary/good_response.dart';
import 'package:satu/core/models/dictionary/good_row_data.dart';
import 'package:satu/core/models/entity_data/transaction_data.dart';
import 'package:satu/views/dictionaries/category/category_edit.dart';
import 'package:satu/views/dictionaries/category/category_select_view.dart';
import 'package:satu/views/dictionaries/contragents/contragents_edit.dart';
import 'package:satu/views/dictionaries/goods/goods_edit.dart';
import 'package:satu/views/login/login_view.dart';
import 'package:satu/views/main/main_view.dart';
@ -73,13 +76,20 @@ Route<dynamic> generateRoute(RouteSettings settings) {
routeName: settings.name,
viewToShow: SelectContragentView(),
);
case contragentEditRoute:
final ContragentResponseEntity contragent =
settings.arguments! as ContragentResponseEntity;
return _getPageRoute(
routeName: settings.name,
viewToShow: ContragentEdit(contragent: contragent),
);
case paymentViewRoute:
return _getPageRoute(
routeName: settings.name,
viewToShow: const PaymentView(),
);
case categoryEditRoute:
final CategoryRowDao category = settings.arguments! as CategoryRowDao;
final CategoryResponse category = settings.arguments! as CategoryResponse;
return _getPageRoute(
routeName: settings.name,
viewToShow: CategoryEdit(
@ -92,7 +102,7 @@ Route<dynamic> generateRoute(RouteSettings settings) {
viewToShow: CategorySelectView(),
);
case goodsEditRoute:
final GoodRowDao good = settings.arguments! as GoodRowDao;
final GoodResponse good = settings.arguments! as GoodResponse;
return _getPageRoute(
routeName: settings.name,
viewToShow: GoodEdit(

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/models/dialog_models.dart';
import 'package:satu/core/models/dictionary/category_response.dart';
import 'package:satu/core/models/dictionary/category_row_data.dart';
import 'package:satu/core/services/dialog_service.dart';
import 'package:satu/core/services/dictionary_service.dart';
@ -10,19 +11,17 @@ import 'package:satu/core/utils/locator.dart';
import 'package:satu/core/utils/logger.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/views/dictionaries/category/category_view.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/buttons/busy_button.dart';
import 'package:satu/widgets/fields/input_field.dart';
import 'package:satu/widgets/fields/line_tile.dart';
import 'package:satu/widgets/fields/note_text.dart';
class CategoryEdit extends StatefulWidget {
const CategoryEdit({
required this.category,
Key? key,
}) : super(key: key);
final CategoryRowDao category;
final CategoryResponse category;
@override
_CategoryEditState createState() => _CategoryEditState();
@ -35,18 +34,17 @@ class _CategoryEditState extends State<CategoryEdit> {
final Logger log = getLogger('_CategoryEditState');
late TextEditingController _controller;
String parentCategoryName = '';
int parentCategoryId = 0;
String? parentCategoryName;
int? parentCategoryId;
@override
void initState() {
super.initState();
if (widget.category.parentId != null) {
parentCategoryId = widget.category.parentId!;
parentCategoryId = widget.category.parentId;
parentCategoryName = widget.category.parentId.toString();
}
_controller = TextEditingController(text: widget.category.name);
getAndStateCategoryName(parentCategoryId);
}
@override
@ -55,24 +53,7 @@ class _CategoryEditState extends State<CategoryEdit> {
super.dispose();
}
Future<void> getAndStateCategoryName(int id) async {
String name = '';
if (id == 0) {
name = 'Корневая категория';
} else {
log.i('message $id');
final Category? category = await _dictionaryService.getCategoryById(id);
if (category != null) {
name = category.name;
}
log.i('message $name');
}
setState(() {
parentCategoryName = name;
parentCategoryId = id;
});
}
@override
Widget build(BuildContext context) {
@ -89,7 +70,7 @@ class _CategoryEditState extends State<CategoryEdit> {
children: [
verticalSpaceSmall,
LineTile(
parentCategoryName,
parentCategoryName ?? 'Корневая категория',
onTap: selectCategory,
labelText: 'Родительская категория',
),
@ -133,8 +114,11 @@ class _CategoryEditState extends State<CategoryEdit> {
Future<void> selectCategory() async {
final dynamic result =
await _navigatorService.push(categorySelectViewRoute);
if (result != null) {
getAndStateCategoryName(result as int);
}
CategoryResponse? category = result as CategoryResponse?;
setState(() {
parentCategoryId = category?.id;
parentCategoryName = category?.name;
});
}
}

View File

@ -1,13 +1,13 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/models/dictionary/category_response.dart';
import 'package:satu/core/models/dictionary/category_row_data.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/services/dictionary_service.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/views/dictionaries/component/dictionary_list_tile.dart';
@ -16,8 +16,6 @@ import 'package:satu/widgets/bar/products_title_bar.dart';
import 'package:satu/widgets/fields/input_field.dart';
import 'package:satu/widgets/fields/line_checkbox.dart';
import 'category_view.dart';
class CategorySelectView extends StatefulWidget {
@override
_CategorySelectViewState createState() => _CategorySelectViewState();
@ -29,38 +27,41 @@ class _CategorySelectViewState extends State<CategorySelectView> {
late TextEditingController _searchTextController;
final FocusNode _searchFocusNode = FocusNode();
late List<Category> _categories = [];
late List<CategoryRowDao> items = [];
static const _pageSize = 20;
String query = '';
Timer? _debounce;
final PagingController<int, CategoryResponse> _pagingController =
PagingController(firstPageKey: 1);
@override
void initState() {
_searchTextController = TextEditingController();
_searchTextController.addListener(() {
if (_searchTextController.text.isNotEmpty) {
searchByField(_searchTextController.text);
} else {
reset();
}
setState(() {
query = _searchTextController.text;
});
if (_debounce?.isActive ?? false) _debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
_pagingController.refresh();
});
});
_pagingController.addPageRequestListener((pageKey) {
_fetchData(pageKey, _pageSize, query);
});
initQuery();
super.initState();
}
Future<void> initQuery() async {
_categories = await _dictionaryService.getCategoriesAll();
searchByField('');
}
@override
void dispose() {
_debounce?.cancel();
_pagingController.dispose();
_searchTextController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
Future<void> handlerCategory(int id) async {
_navigatorService.pop(id);
Future<void> handlerCategory(CategoryResponse? category) async {
_navigatorService.pop(category);
}
@override
@ -82,43 +83,47 @@ class _CategorySelectViewState extends State<CategorySelectView> {
'Корневая категория',
value: true,
labelText: 'По умолчанию',
onTap: () => handlerCategory(0),
onTap: () => handlerCategory(null),
),
const ProductsTitleBarBar(title: 'Выберите категорию'),
Expanded(
child: ListView.separated(
child: PagedListView<int, CategoryResponse>.separated(
physics: const BouncingScrollPhysics(),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
final CategoryRowDao category = items[index];
return DictionaryTile(
key: Key('category_${category.id}'),
onPress: () => handlerCategory(category.id!),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
category.name,
style: const TextStyle(fontSize: 12, color: textColor),
),
Text(
category.parentName.isEmpty
? 'Корневая категория'
: 'Родитель: ${category.parentName}',
style: const TextStyle(
fontSize: 10, color: placeholderColor)),
],
),
);
},
separatorBuilder: (BuildContext context, int index) {
return const Divider(
height: 1.0,
color: disableColor,
);
},
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<CategoryResponse>(
itemBuilder: (BuildContext context, CategoryResponse category,
int index) {
return DictionaryTile(
key: Key('category_${category.id}'),
onPress: () => handlerCategory(category),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
category.name,
style:
const TextStyle(fontSize: 12, color: textColor),
),
Text(
category.parentId == null
? 'Корневая категория'
: 'Родитель: ${category.parentId}',
style: const TextStyle(
fontSize: 10, color: placeholderColor)),
],
),
);
},
),
),
),
)
],
),
);
@ -126,28 +131,18 @@ class _CategorySelectViewState extends State<CategorySelectView> {
void reset() {
_searchTextController.clear();
searchByField('');
}
void searchByField(String query) async {
final List<CategoryRowDao> list = [];
final Iterable<Category> filtered = query == ''
? _categories
: _categories.where((element) =>
element.name.toLowerCase().contains(query.toLowerCase()));
filtered.forEach((element) {
final Category category = _categories
.firstWhere((parent) => parent.id == element.parentId, orElse: () {
return Category();
});
final String parentName = category.name;
final CategoryRowDao rowDao = CategoryRowDao(
element.name, parentName, element.id,
parentId: element.parentId);
list.add(rowDao);
});
setState(() {
items = list;
});
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
final List<CategoryResponse> newItems = await _dictionaryService
.getCategories(page: pageKey, query: query, perpage: perPage);
final isLastPage = newItems.length < _pageSize;
if (isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + 1;
_pagingController.appendPage(newItems, nextPageKey);
}
}
}

View File

@ -1,15 +1,16 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/models/dictionary/category_response.dart';
import 'package:satu/core/models/dictionary/category_row_data.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/services/dictionary_service.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/views/dictionaries/component/dictionary_list_tile.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/bar/products_title_bar.dart';
@ -26,31 +27,36 @@ class _CategoryDictionaryViewState extends State<CategoryDictionaryView> {
late TextEditingController _searchTextController;
final FocusNode _searchFocusNode = new FocusNode();
late List<Category> _categories = [];
late List<CategoryRowDao> items = [];
static const _pageSize = 20;
String query = '';
Timer? _debounce;
final PagingController<int, CategoryResponse> _pagingController =
PagingController(firstPageKey: 1);
@override
void initState() {
_searchTextController = TextEditingController();
_searchTextController.addListener(() {
if (_searchTextController.text.isNotEmpty) {
searchByField(_searchTextController.text);
} else {
reset();
}
setState(() {
query = _searchTextController.text;
});
if (_debounce?.isActive ?? false) _debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
_pagingController.refresh();
});
});
_pagingController.addPageRequestListener((pageKey) {
_fetchData(pageKey, _pageSize, query);
});
initQuery();
super.initState();
}
Future<void> initQuery() async {
_categories = await _dictionaryService.getCategoriesAll();
searchByField('');
}
@override
void dispose() {
_debounce?.cancel();
_pagingController.dispose();
_searchTextController.dispose();
_searchFocusNode.dispose();
super.dispose();
@ -73,40 +79,43 @@ class _CategoryDictionaryViewState extends State<CategoryDictionaryView> {
),
const ProductsTitleBarBar(title: 'Список категории'),
Expanded(
child: ListView.separated(
child: PagedListView<int, CategoryResponse>.separated(
physics: const BouncingScrollPhysics(),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
final CategoryRowDao category = items[index];
return DictionaryTile(
key: Key('category_${category.id}'),
onPress: () => _navigatorService.push(categoryEditRoute,
arguments: category),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
category.name,
style: const TextStyle(fontSize: 12, color: textColor),
),
Text(
category.parentName.isEmpty
? 'Корневая категория'
: 'Родитель: ${category.parentName}',
style: const TextStyle(
fontSize: 10, color: placeholderColor)),
],
),
);
},
separatorBuilder: (BuildContext context, int index) {
return const Divider(
height: 1.0,
color: disableColor,
);
},
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<CategoryResponse>(
itemBuilder: (BuildContext context, CategoryResponse category,
int index) {
return DictionaryTile(
key: Key('category_${category.id}'),
onPress: () => _navigatorService.push(categoryEditRoute,
arguments: category),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
category.name,
style:
const TextStyle(fontSize: 12, color: textColor),
),
Text(
category.parentId ==null
? 'Корневая категория'
: 'Родитель: ${category.parentId}',
style: const TextStyle(
fontSize: 10, color: placeholderColor)),
],
),
);
},
),
),
),
)
],
),
floatingActionButton: FloatingActionButton(
@ -124,30 +133,18 @@ class _CategoryDictionaryViewState extends State<CategoryDictionaryView> {
void reset() {
_searchTextController.clear();
searchByField('');
}
void searchByField(String query) async {
log.i(query);
final List<CategoryRowDao> list = [];
final Iterable<Category> filtered = query == ''
? _categories
: _categories.where((element) =>
element.name.toLowerCase().contains(query.toLowerCase()));
filtered.forEach((element) {
final Category category = _categories
.firstWhere((parent) => parent.id == element.parentId, orElse: () {
return Category();
});
final String parentName = category.name;
final CategoryRowDao rowDao = CategoryRowDao(
element.name, parentName, element.id,
parentId: element.parentId);
list.add(rowDao);
});
setState(() {
items = list;
});
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
final List<CategoryResponse> newItems = await _dictionaryService
.getCategories(page: pageKey, query: query, perpage: perPage);
final isLastPage = newItems.length < _pageSize;
if (isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + 1;
_pagingController.appendPage(newItems, nextPageKey);
}
}
}

View File

@ -0,0 +1,170 @@
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import 'package:satu/core/models/dialog_models.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/core/services/dialog_service.dart';
import 'package:satu/core/services/dictionary_service.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/core/utils/logger.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/buttons/busy_button.dart';
import 'package:satu/widgets/fields/input_checkbox.dart';
import 'package:satu/widgets/fields/input_field.dart';
class ContragentEdit extends StatefulWidget {
const ContragentEdit({
required this.contragent,
Key? key,
}) : super(key: key);
final ContragentResponseEntity contragent;
@override
_ContragentEditState createState() => _ContragentEditState();
}
class _ContragentEditState extends State<ContragentEdit> {
final NavigatorService _navigatorService = locator<NavigatorService>();
final DictionaryService _dictionaryService = locator<DictionaryService>();
final DialogService _dialogService = locator<DialogService>();
final Logger log = getLogger('_GoodEditState');
late TextEditingController _controllerName;
late TextEditingController _controllerBinIin;
late TextEditingController _controllerPhone;
late TextEditingController _controllerMail;
late bool _isNds;
late bool _isResident;
String parentCategoryName = '';
int? parentCategoryId;
@override
void initState() {
super.initState();
_controllerName = TextEditingController(text: widget.contragent.name ?? '');
_controllerBinIin =
TextEditingController(text: widget.contragent.biniin ?? '');
_controllerPhone =
TextEditingController(text: widget.contragent.phone ?? '');
_controllerMail =
TextEditingController(text: widget.contragent.email ?? '');
_isNds = widget.contragent.nds == 1;
_isResident = widget.contragent.resident == 1;
}
@override
void dispose() {
_controllerName.dispose();
super.dispose();
}
void save() async {
ContragentResponseEntity contragent = widget.contragent;
contragent.name = _controllerName.text;
contragent.biniin = _controllerBinIin.text;
contragent.phone = _controllerPhone.text;
contragent.email = _controllerMail.text;
contragent.nds = _isNds ? 1 : 0;
contragent.resident = _isResident ? 1 : 0;
String? message = await _dictionaryService.saveContragent(contragent);
if (message != null) {
_dialogService.showDialog(description: message);
} else {
_navigatorService.pop(true);
}
}
void delete() async {
ContragentResponseEntity contragent = widget.contragent;
String? message = await _dictionaryService.deleteContragent(contragent);
if (message != null) {
_dialogService.showDialog(description: message);
} else {
_navigatorService.pop(true);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ProductsAppBar(
title: widget.contragent.id == null
? 'Добавление контрагента'
: 'Редактирование контрагента',
),
body: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
verticalSpaceSmall,
InputField(
controller: _controllerName,
labelText: 'Наименование',
placeholder: 'Введите наименование контрагента',
),
InputField(
controller: _controllerBinIin,
labelText: 'БИН/ИИН>',
placeholder: 'Введите БИН/ИИН',
),
InputField(
controller: _controllerPhone,
labelText: 'Телефон',
placeholder: 'Введите номер телефона',
),
InputField(
controller: _controllerMail,
labelText: 'E-mail"',
placeholder: 'Введите электронную почту',
),
InputCheckBox('НДС', value: _isNds, labelText: 'Плательщик НДС',
onChanged: (value) {
setState(() {
_isNds = value ?? false;
});
}),
InputCheckBox('', value: _isResident, labelText: 'Резидент',
onChanged: (value) {
setState(() {
_isResident = value ?? false;
});
}),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 45.0, vertical: 20.0),
child: BusyButton(
title: 'СОХРАНИТЬ',
onPressed: () {
save();
}),
),
if (widget.contragent.id != null)
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 45.0, vertical: 20.0),
child: BusyButton(
title: 'УДАЛИТЬ',
onPressed: () async {
DialogResponse response =
await _dialogService.showConfirmationDialog(
title: 'Внимание',
description:
'Вы уверены, что хотите удалить категорию?',
confirmationTitle: 'Удалить',
cancelTitle: 'Отмена');
if (response.confirmed) {
delete();
}
},
isDanger: true,
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,141 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/core/models/dictionary/good_row_data.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/services/dictionary_service.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/views/dictionaries/component/dictionary_list_tile.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/bar/products_title_bar.dart';
import 'package:satu/widgets/fields/input_field.dart';
class ContragentsDictionaryView extends StatefulWidget {
@override
_ContragentsDictionaryViewState createState() =>
_ContragentsDictionaryViewState();
}
class _ContragentsDictionaryViewState extends State<ContragentsDictionaryView> {
final DictionaryService _dictionaryService = locator<DictionaryService>();
final NavigatorService _navigatorService = locator<NavigatorService>();
late TextEditingController _searchTextController;
final FocusNode _searchFocusNode = FocusNode();
late List<ContragentResponseEntity> items = [];
static const _pageSize = 20;
final PagingController<int, ContragentResponseEntity> _pagingController =
PagingController(firstPageKey: 0);
@override
void initState() {
_searchTextController = TextEditingController();
_searchTextController.addListener(() {
if (_searchTextController.text.isNotEmpty) {
//searchByField(_searchTextController.text);
} else {
reset();
}
});
_pagingController.addPageRequestListener((pageKey) {
_fetchData(pageKey, _pageSize, null);
});
super.initState();
}
Future<void> initQuery() async {
//searchByField('');
}
@override
void dispose() {
_searchTextController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ProductsAppBar(
title: 'Контрагенты',
drawerShow: true,
),
body: Column(
children: [
InputField(
placeholder: 'Поиск по наименованию',
search: true,
controller: _searchTextController,
fieldFocusNode: _searchFocusNode,
),
const ProductsTitleBarBar(title: 'Список контрагентов'),
Expanded(
child: PagedListView<int, ContragentResponseEntity>(
pagingController: _pagingController,
builderDelegate:
PagedChildBuilderDelegate<ContragentResponseEntity>(
itemBuilder: (BuildContext context,
ContragentResponseEntity entity, int index) {
return DictionaryTile(
key: Key('contragent_${entity.id}'),
onPress: () async {
final dynamic result = await _navigatorService
.push(contragentEditRoute, arguments: entity);
if (result != null && true == (result as bool)) {
//searchByField('');
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
entity.name ?? '',
style: const TextStyle(fontSize: 12, color: textColor),
),
Text('БИН/ИИН: ${entity.biniin}',
style: const TextStyle(
fontSize: 10, color: placeholderColor)),
],
),
);
},
),
))
],
),
floatingActionButton: FloatingActionButton(
elevation: 2,
onPressed: () => locator<NavigatorService>().push(contragentEditRoute,
arguments: ContragentResponseEntity()..refAppCompanyTypeId = 5),
child: const Icon(
Icons.add_rounded,
size: 34.0,
color: whiteColor,
),
),
);
}
void reset() {
_searchTextController.clear();
}
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
final List<ContragentResponseEntity> newItems = await _dictionaryService
.getContragents(page: pageKey, query: query, perpage: perPage);
final isLastPage = newItems.length < _pageSize;
if (isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + newItems.length;
_pagingController.appendPage(newItems, nextPageKey);
}
}
}

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/models/dialog_models.dart';
import 'package:satu/core/models/dictionary/category_row_data.dart';
import 'package:satu/core/models/dictionary/good_response.dart';
import 'package:satu/core/models/dictionary/good_row_data.dart';
import 'package:satu/core/services/dialog_service.dart';
import 'package:satu/core/services/dictionary_service.dart';
@ -11,19 +11,17 @@ import 'package:satu/core/utils/locator.dart';
import 'package:satu/core/utils/logger.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/views/dictionaries/category/category_view.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/buttons/busy_button.dart';
import 'package:satu/widgets/fields/input_field.dart';
import 'package:satu/widgets/fields/line_tile.dart';
import 'package:satu/widgets/fields/note_text.dart';
class GoodEdit extends StatefulWidget {
const GoodEdit({
required this.good,
Key? key,
}) : super(key: key);
final GoodRowDao good;
final GoodResponse good;
@override
_GoodEditState createState() => _GoodEditState();
@ -44,10 +42,11 @@ class _GoodEditState extends State<GoodEdit> {
super.initState();
if (widget.good.categoryId != null) {
parentCategoryId = widget.good.categoryId;
parentCategoryName = widget.good.categoryName ?? '';
}
_controller = TextEditingController(text: widget.good.name);
getAndStateCategoryName(parentCategoryId);
//getAndStateCategoryName(parentCategoryId);
}
@override
@ -56,22 +55,22 @@ class _GoodEditState extends State<GoodEdit> {
super.dispose();
}
Future<void> getAndStateCategoryName(int? id) async {
String name = '';
if (id == null) {
} else if (id == 0) {
name = 'Корневая категория';
} else {
final Category? category = await _dictionaryService.getCategoryById(id);
if (category != null) {
name = category.name;
}
}
setState(() {
parentCategoryName = name;
parentCategoryId = id;
});
}
// Future<void> getAndStateCategoryName(int? id) async {
// String name = '';
// if (id == null) {
// } else if (id == 0) {
// name = 'Корневая категория';
// } else {
// final Category? category = await _dictionaryService.getCategoryById(id);
// if (category != null) {
// name = category.name;
// }
// }
// setState(() {
// parentCategoryName = name;
// parentCategoryId = id;
// });
// }
@override
Widget build(BuildContext context) {
@ -166,7 +165,7 @@ class _GoodEditState extends State<GoodEdit> {
final dynamic result =
await _navigatorService.push(categorySelectViewRoute);
if (result != null) {
getAndStateCategoryName(result as int);
//getAndStateCategoryName(result as int);
}
}
}

View File

@ -1,7 +1,11 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/models/dictionary/good_response.dart';
import 'package:satu/core/models/dictionary/good_row_data.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/services/dictionary_service.dart';
@ -25,33 +29,35 @@ class _GoodsDictionaryViewState extends State<GoodsDictionaryView> {
final NavigatorService _navigatorService = locator<NavigatorService>();
late TextEditingController _searchTextController;
final FocusNode _searchFocusNode = FocusNode();
static const _pageSize = 20;
String query = '';
Timer? _debounce;
late List<Good> _goods = [];
late List<Category> _categories = [];
late List<GoodRowDao> items = [];
final PagingController<int, GoodResponse> _pagingController =
PagingController(firstPageKey: 1);
@override
void initState() {
_searchTextController = TextEditingController();
_searchTextController.addListener(() {
if (_searchTextController.text.isNotEmpty) {
searchByField(_searchTextController.text);
} else {
reset();
}
setState(() {
query = _searchTextController.text;
});
if (_debounce?.isActive ?? false) _debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
_pagingController.refresh();
});
});
_pagingController.addPageRequestListener((pageKey) {
_fetchData(pageKey, _pageSize, query);
});
initQuery();
super.initState();
}
Future<void> initQuery() async {
_goods = await _dictionaryService.getGoodsByNameOrEan('');
_categories = await _dictionaryService.getCategoriesAll();
searchByField('');
}
@override
void dispose() {
_debounce?.cancel();
_pagingController.dispose();
_searchTextController.dispose();
_searchFocusNode.dispose();
super.dispose();
@ -94,37 +100,40 @@ class _GoodsDictionaryViewState extends State<GoodsDictionaryView> {
),
const ProductsTitleBarBar(title: 'Список товаров'),
Expanded(
child: ListView.separated(
physics: const BouncingScrollPhysics(),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
final GoodRowDao good = items[index];
return DictionaryTile(
onPress: () {
locator<NavigatorService>()
.push(goodsEditRoute, arguments: good);
child: PagedListView<int, GoodResponse>.separated(
physics: const BouncingScrollPhysics(),
separatorBuilder: (BuildContext context, int index) {
return const Divider(
height: 1.0,
color: disableColor,
);
},
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<GoodResponse>(
itemBuilder:
(BuildContext context, GoodResponse good, int index) {
return DictionaryTile(
onPress: () {
locator<NavigatorService>()
.push(goodsEditRoute, arguments: good);
},
child: ProductTitleWidget(
name: good.name,
categoryName: good.categoryName,
ean: good.ean,
),
);
},
child: ProductTitleWidget(
name: good.name,
categoryName: good.categoryName,
ean: good.ean,
),
);
},
separatorBuilder: (BuildContext context, int index) {
return const Divider(
height: 1.0,
color: disableColor,
);
},
),
),
),
),
)
],
),
floatingActionButton: FloatingActionButton(
elevation: 2,
onPressed: () => locator<NavigatorService>()
.push(goodsEditRoute, arguments: GoodRowDao('', '')),
onPressed: () =>
locator<NavigatorService>()
.push(goodsEditRoute, arguments: GoodRowDao('', '')),
child: const Icon(
Icons.add_rounded,
size: 34.0,
@ -136,30 +145,18 @@ class _GoodsDictionaryViewState extends State<GoodsDictionaryView> {
void reset() {
_searchTextController.clear();
searchByField('');
}
Future<void> searchByField(String query) async {
log.i(query);
final List<GoodRowDao> list = [];
final Iterable<Good> filtered = query == ''
? _goods
: _goods.where((element) =>
element.name.toLowerCase().contains(query.toLowerCase()) ||
(element.ean != null &&
element.ean!.contains(query.toLowerCase())));
filtered.forEach((element) {
final Category category = _categories
.firstWhere((parent) => parent.id == element.categoryId, orElse: () {
return Category();
});
final String parentName = category.name;
final GoodRowDao rowDao = GoodRowDao(element.name, parentName,
ean: element.ean, id: element.id, categoryId: element.categoryId);
list.add(rowDao);
});
setState(() {
items = list;
});
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
final List<GoodResponse> newItems = await _dictionaryService.getGoods(
page: pageKey, query: query, perpage: perPage);
final isLastPage = newItems.length < _pageSize;
if (isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + 1;
_pagingController.appendPage(newItems, nextPageKey);
}
}
}

View File

@ -1,6 +1,3 @@
import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -12,7 +9,6 @@ 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/routes/route_names.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';
@ -52,57 +48,55 @@ class _LoginViewState extends State<LoginView> {
return StoreConnector<AppState, UserState>(
converter: (store) => store.state.userState!,
builder: (context, vm) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const LogoSatu(),
InputField(
placeholder: 'Введите почту',
controller: emailController,
textInputType: TextInputType.emailAddress,
nextFocusNode: passwordNode,
),
verticalSpaceSmall,
InputField(
placeholder: 'Введите пароль',
password: true,
controller: passwordController,
fieldFocusNode: passwordNode,
enterPressed: _pressBtnEnter,
textInputAction: TextInputAction.done,
),
verticalSpaceMedium,
Padding(
padding:
EdgeInsets.only(left: 45.sp, right: 45.sp, top: 30.sp),
child: BusyButton(
title: 'ВОЙТИ',
busy: vm.isLoading!,
onPressed: _pressBtnEnter,
),
),
verticalSpaceLarge,
IconButton(
icon: const Icon(MdiIcons.qrcodeScan),
iconSize: ScreenUtil().setSp(40.0),
tooltip: 'Scan',
onPressed: scan,
)
],
return Scaffold(body: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const LogoSatu(),
InputField(
placeholder: 'Введите почту',
controller: emailController,
textInputType: TextInputType.emailAddress,
nextFocusNode: passwordNode,
),
),
);
},
));
verticalSpaceSmall,
InputField(
placeholder: 'Введите пароль',
password: true,
controller: passwordController,
fieldFocusNode: passwordNode,
enterPressed: _pressBtnEnter,
textInputAction: TextInputAction.done,
),
verticalSpaceMedium,
Padding(
padding: EdgeInsets.only(
left: 45.sp, right: 45.sp, top: 30.sp),
child: BusyButton(
title: 'ВОЙТИ',
busy: vm.isLoading!,
onPressed: _pressBtnEnter,
),
),
verticalSpaceLarge,
IconButton(
icon: const Icon(MdiIcons.qrcodeScan),
iconSize: ScreenUtil().setSp(40.0),
tooltip: 'Scan',
onPressed: scan,
)
],
),
),
);
},
));
});
}
@ -121,43 +115,14 @@ class _LoginViewState extends State<LoginView> {
_dialogService.showDialog(description: 'Не верный формат QR кода');
}
}
// try {
// var options = ScanOptions(strings: {
// "cancel": 'Отмена',
// "flash_on": 'Вкл фонарик',
// "flash_off": 'Выкл фонарик',
// });
// var result = await BarcodeScanner.scan(options: options);
// print(result.type); // The result type (barcode, cancelled, failed)
// print(result.rawContent); // The barcode content
// print(result.format); // The barcode format (as enum)
// print(result.formatNote); // If a unknown format was scanned this field contains a note
// if (result.type == ResultType.Barcode && result.rawContent?.length == 60) {
// //Redux.store.dispatch(authenticateToken(result.rawContent));
// } else if (result.type == ResultType.Error) {
// _dialogService.showDialog(description: 'Не верный формат QR кода');
// }
// } on PlatformException catch (e) {
// var result = ScanResult.create();
// result.type = ResultType.Error;
// result.format = BarcodeFormat.unknown;
// if (e.code == BarcodeScanner.cameraAccessDenied) {
// result.rawContent = 'The user did not grant the camera permission!';
// _dialogService.showDialog(description: 'Нет доступа до камеры устройства');
// } else {
// result.rawContent = 'Unknown error: $e';
// _dialogService.showDialog(description: 'Неизвестная ошибка: $e');
// }
// }
}
}
class LoginModel {
LoginModel(
{required this.authType, required this.login, required this.password});
final String authType;
final String login;
final String password;
LoginModel(
{required this.authType, required this.login, required this.password});
}

View File

@ -7,11 +7,12 @@ import 'package:satu/core/utils/locator.dart';
import 'package:satu/views/analytics/analytics_view.dart';
import 'package:satu/views/dictionaries/category/category_view.dart';
import 'package:satu/views/dictionaries/goods/goods_view.dart';
import 'package:satu/views/settings/printer_bluetooth/printer_view.dart';
import 'package:satu/views/settings/setting_view.dart';
import 'package:satu/views/work/work_view.dart';
import 'package:satu/widgets/drawer/app_drawer.dart';
import '../dictionaries/contragents/contragents_view.dart';
class MainView extends StatefulWidget {
@override
_MainViewState createState() => _MainViewState();
@ -25,6 +26,7 @@ class _MainViewState extends State<MainView> {
final _settingsView = SettingsView();
final _categoryDictView = CategoryDictionaryView();
final _goodDictView = GoodsDictionaryView();
final _contragentDictView = ContragentsDictionaryView();
final _analyticsView = const AnalyticsView();
Widget _body(Type viewClass) {
@ -40,6 +42,9 @@ class _MainViewState extends State<MainView> {
if(viewClass == GoodsDictionaryView) {
return _goodDictView;
}
if(viewClass == ContragentsDictionaryView) {
return _contragentDictView;
}
if(viewClass == AnalyticsView) {
return _analyticsView;
}

View File

@ -1,6 +1,3 @@
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
// import 'package:bluetooth_print/bluetooth_print.dart';
// import 'package:bluetooth_print/bluetooth_print_model.dart';

View File

@ -1,4 +1,3 @@
import 'dart:io';
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
import 'package:flutter/material.dart';

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/bar/products_title_bar.dart';

View File

@ -1,14 +1,11 @@
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter/material.dart';
import 'package:satu/core/models/auth/auth_response.dart';
import 'package:satu/core/redux/actions/user_actions.dart';
import 'package:satu/core/redux/state/user_state.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/services/api_service.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/app_colors.dart';
@ -19,7 +16,6 @@ class StartUpView extends StatefulWidget {
class _StartUpViewState extends State<StartUpView> {
final NavigatorService _navigation = locator<NavigatorService>();
final ApiService _api = locator<ApiService>();
@override
void initState() {

View File

@ -1,7 +1,4 @@
import 'package:flutter/material.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/shared/shared_styles.dart';
import '../../../widgets/bar/products_app_bar.dart';

View File

@ -4,13 +4,11 @@ import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/shared_styles.dart';
import 'package:satu/widgets/dialog/modal_select_dialog.dart';
class ContragentSelectBar extends StatelessWidget {
final String value;
const ContragentSelectBar({Key? key, required this.value}) : super(key: key);
const ContragentSelectBar({required this.value, Key? key}) : super(key: key);
final String value;
@override
Widget build(BuildContext context) {

View File

@ -2,12 +2,12 @@ import 'package:flutter/material.dart';
class CustomField extends StatelessWidget {
CustomField({@required this.hintText, @required this.iconData, this.label});
final String? hintText;
final IconData? iconData;
final String? label;
CustomField({@required this.hintText, @required this.iconData, this.label});
@override
Widget build(BuildContext context) {
return Container(

View File

@ -20,11 +20,11 @@ Future dialog(BuildContext cont) async {
const Expanded(
flex: 1,
child: Text(
"Sample type",
'Sample type',
style: TextStyle(fontWeight: FontWeight.w700),
),
),
Expanded(flex: 1, child: Text("123"))
Expanded(flex: 1, child: Text('123'))
],
),
],

View File

@ -1,6 +1,4 @@
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';
@ -15,7 +13,6 @@ import 'package:satu/shared/shared_styles.dart';
import 'package:satu/views/work/views/add_by_barcode/add_by_barcode_view.dart';
import 'package:satu/widgets/ui/product_title_widget.dart';
import 'dialog_edit_product.dart';
class ProductListItem extends StatefulWidget {
const ProductListItem(

View File

@ -2,67 +2,61 @@ import 'package:flutter/material.dart';
class TransactionItem extends StatelessWidget {
TransactionItem(
{required this.fullName,
required this.status,
required this.amount,
required this.received});
final String fullName;
final String status;
final String amount;
final bool received;
TransactionItem({required this.fullName, required this.status, required this.amount, required this.received});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Container(
width: 16,
height: 50,
//margin: EdgeInsets.only(right: 16),
// child: Icon(
// Icons.memory
// ),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
fullName,
style: TextStyle(
//color: kPrimaryColor,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
status,
style: TextStyle(
//color: kGreyColor,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
],
child: Row(children: [
Container(
width: 16,
height: 50,
//margin: EdgeInsets.only(right: 16),
// child: Icon(
// Icons.memory
// ),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
fullName,
style: TextStyle(
//color: kPrimaryColor,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
Text(
(received ? "+" : "-") + r" $ " + amount + " KZT",
style: TextStyle(
color: received ? Colors.green : Colors.red,
fontSize: 16,
fontWeight: FontWeight.bold,
Text(
status,
style: TextStyle(
//color: kGreyColor,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
]
),
],
),
),
Text(
(received ? '+' : '-') + r' $ ' + amount + ' KZT',
style: TextStyle(
color: received ? Colors.green : Colors.red,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
]),
);
}
}
}

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:grouped_list/grouped_list.dart';
import 'package:satu/core/models/entity_data/transaction_data.dart';
import 'package:satu/core/models/flow/dao/transaction_dao.dart';
import 'package:satu/core/redux/actions/journal_actions.dart';
import 'package:satu/core/redux/state/journal_state.dart';
@ -14,7 +13,6 @@ import 'package:satu/shared/app_colors.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/buttons/option_pill.dart';
import 'component/journal_list_tile.dart';
import 'component/transaction_item.dart';
class JournalView extends StatefulWidget {
@override

View File

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -138,13 +137,13 @@ class SellView extends StatelessWidget {
final dynamic result =
await _nav.push(addByBarcodeViewRoute);
if (result != null) {
final List<Good> goods =
await locator<DictionaryService>()
.getGoodsByEan(result as String);
if (goods.isNotEmpty) {
Redux.store
?.dispatch(addSellItem(good: goods.first));
}
// final List<Good> goods =
// await locator<DictionaryService>()
// .getGoodsByEan(result as String);
// if (goods.isNotEmpty) {
// Redux.store
// ?.dispatch(addSellItem(good: goods.first));
// }
}
},
child: Icon(Icons.qr_code_rounded,

View File

@ -1,6 +1,4 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';

View File

@ -26,25 +26,21 @@ class _AddProductViewState extends State<AddProductView> {
late TextEditingController _searchTextController;
final FocusNode _searchFocusNode = new FocusNode();
List<Category>? _history;
List<Category>? _categories;
List<Good>? _goods;
@override
void initState() {
_searchTextController = TextEditingController();
_searchTextController.addListener(() {
if(_searchTextController.text.isNotEmpty){
searchByField(_searchTextController.text);
if (_searchTextController.text.isNotEmpty) {
searchByField(_searchTextController.text);
} else {
reset();
reset();
}
});
_history = [Category()
..id = 0
];
_history = [Category()..id = 0];
_categories = [];
_goods = [];
super.initState();
@ -63,15 +59,21 @@ class _AddProductViewState extends State<AddProductView> {
int catSize = _categories?.length ?? 0;
int goodSize = _goods?.length ?? 0;
return Scaffold(
appBar: ProductsAppBar( title: 'Категория',),
appBar: ProductsAppBar(
title: 'Категория',
),
body: Column(
children: [
InputField(placeholder: 'Поиск по наименованию или коду товара',
InputField(
placeholder: 'Поиск по наименованию или коду товара',
search: true,
controller: _searchTextController,
fieldFocusNode: _searchFocusNode,),
fieldFocusNode: _searchFocusNode,
),
verticalSpaceTiny,
ProductsTitleBarBar(title: goodSize > 0 ? 'Выберите товар' : 'Выберите категорию',),
ProductsTitleBarBar(
title: goodSize > 0 ? 'Выберите товар' : 'Выберите категорию',
),
Expanded(
child: ListView.separated(
physics: BouncingScrollPhysics(),
@ -94,14 +96,17 @@ class _AddProductViewState extends State<AddProductView> {
categoryName: _history?.last.name,
onPress: () {
onGoodPress(good);
} ,
},
);
}, separatorBuilder: (BuildContext context, int index) {
return Divider(height: 1.0, color: disableColor,);
},
},
separatorBuilder: (BuildContext context, int index) {
return Divider(
height: 1.0,
color: disableColor,
);
},
),
),
],
),
);
@ -118,16 +123,16 @@ class _AddProductViewState extends State<AddProductView> {
}
void reset() {
_history = [Category()
..id = 0
];
navigateCategory(0);
_searchTextController.clear();
}
_history = [Category()..id = 0];
navigateCategory(0);
_searchTextController.clear();
}
void navigateCategory(int categoryId) async {
List<Category> categories = await _dictionaryService.getCategoryByParentId(categoryId);
List<Good> goods = await _dictionaryService.getGoodsByCategoryId(categoryId);
List<Category> categories =
await _dictionaryService.getCategoryByParentId(categoryId);
List<Good> goods =
await _dictionaryService.getGoodsByCategoryId(categoryId);
setState(() {
_categories = categories;
_goods = goods;
@ -142,5 +147,4 @@ class _AddProductViewState extends State<AddProductView> {
_goods = goods;
});
}
}

View File

@ -1,15 +1,12 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/shared_styles.dart';
import 'package:satu/shared/ui_helpers.dart';
class AddCategoryListItem extends StatelessWidget {
final String name;
final Function? onPress;
const AddCategoryListItem({Key? key, this.name = '', this.onPress})
: super(key: key);
final String name;
final Function? onPress;
@override
Widget build(BuildContext context) {

View File

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:satu/shared/app_colors.dart';

View File

@ -1,8 +1,5 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/shared_styles.dart';
import 'package:satu/shared/ui_helpers.dart';
class ContragentListItem extends StatelessWidget {
const ContragentListItem({Key? key, this.name, this.onPress})

View File

@ -1,14 +1,11 @@
import 'package:flutter/material.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/services/dictionary_service.dart';
import 'package:satu/core/services/navigator_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/views/work/views/add_product/component/add_category_list_item.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/bar/products_title_bar.dart';
import 'package:satu/widgets/fields/input_field.dart';

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:satu/core/utils/utils_parse.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({

View File

@ -1,7 +1,5 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:satu/core/models/entity_data/transaction_data.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/services/navigator_service.dart';

View File

@ -1,10 +1,7 @@
import 'dart:convert';
import 'dart:io';
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:satu/core/entity/transaction_entity.dart';
import 'package:satu/core/models/dialog_models.dart';
import 'package:satu/core/models/entity_data/transaction_data.dart';

View File

@ -1,9 +1,7 @@
import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/views/work/tabs/buy_view.dart';
import 'package:satu/views/work/tabs/journal_view.dart';
import 'package:satu/views/work/tabs/sell_view.dart';

View File

@ -2,16 +2,8 @@ import 'package:flutter/material.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/widgets/bar/products_header_bar.dart';
class ProductsAppBar extends StatelessWidget implements PreferredSizeWidget {
final String? title;
final List<Widget>? actions;
final Widget? child;
final double childHeight;
final double elevation;
final Color? backgroundColor;
final bool drawerShow;
const ProductsAppBar(
{Key? key,
@ -23,6 +15,13 @@ class ProductsAppBar extends StatelessWidget implements PreferredSizeWidget {
this.drawerShow = false,
this.backgroundColor = Colors.transparent})
: super(key: key);
final String? title;
final List<Widget>? actions;
final Widget? child;
final double childHeight;
final double elevation;
final Color? backgroundColor;
final bool drawerShow;
@override
Widget build(BuildContext context) {

View File

@ -1,8 +1,5 @@
import 'package:flutter/material.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/widgets/dialog/modal_select_dialog.dart';
class ProductHeaderBar extends StatelessWidget {
const ProductHeaderBar({required this.count, required this.sum , Key? key})

View File

@ -1,7 +1,5 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/shared_styles.dart';
/// A button that shows a busy indicator in place of title
class AmanIconButton extends StatefulWidget {

View File

@ -1,4 +1,3 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:satu/shared/app_colors.dart';
@ -6,6 +5,15 @@ import 'package:satu/shared/shared_styles.dart';
/// A button that shows a busy indicator in place of title
class BusyButton extends StatefulWidget {
const BusyButton({
required this.title,
required this.onPressed,
this.busy = false,
this.enabled = true,
this.isCancel = false,
this.isDanger = false,
});
final bool busy;
final String title;
final Function onPressed;
@ -13,15 +21,6 @@ class BusyButton extends StatefulWidget {
final bool isCancel;
final bool isDanger;
const BusyButton({
required this.title,
this.busy = false,
required this.onPressed,
this.enabled = true,
this.isCancel = false,
this.isDanger = false,
});
@override
_BusyButtonState createState() => _BusyButtonState();
}

View File

@ -1,21 +1,17 @@
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;
DialogManager({Key? key, required this.child}) : super(key: key);
DialogManager({required this.child, Key? key}) : super(key: key);
final Widget child;
_DialogManagerState createState() => _DialogManagerState();
}

View File

@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
class DialogModalSelect extends StatefulWidget {
final String? title;
final String? descriptions;
final String? text;
const DialogModalSelect({Key? key, this.title, this.descriptions, this.text})
: super(key: key);
final String? title;
final String? descriptions;
final String? text;
@override
_DialogModalSelectState createState() => _DialogModalSelectState();
@ -86,7 +86,7 @@ class _DialogModalSelectState extends State<DialogModalSelect> {
radius: avatarRadius,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(avatarRadius)),
child: Image.asset("assets/model.jpeg")),
child: Image.asset('assets/model.jpeg')),
),
)
],

View File

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -12,6 +11,7 @@ import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/views/analytics/analytics_view.dart';
import 'package:satu/views/dictionaries/category/category_view.dart';
import 'package:satu/views/dictionaries/contragents/contragents_view.dart';
import 'package:satu/views/dictionaries/goods/goods_view.dart';
import 'package:satu/views/settings/setting_view.dart';
import 'package:satu/views/work/work_view.dart';
@ -28,62 +28,95 @@ class AppDrawer extends StatelessWidget {
_createHeader(),
_createDrawerSectionTitle(text: 'ОСНОВНОЙ РАЗДЕЛ'),
_createDrawerItem(
svgFile: 'sell',
text: 'Касса',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(WorkView));
},),
svgFile: 'sell',
text: 'Касса',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(WorkView));
},
),
_createDrawerItem(
svgFile: 'analytics',
icon: Icons.analytics,
text: 'Аналитика',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(AnalyticsView));
},),
},
),
_createDrawerItem(
svgFile: 'inventarization',
text: 'Инвентаризация',
disable: true),
icon: Icons.archive,
text: 'Остатки',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(AnalyticsView));
},
disable: true,
),
_createDrawerItem(
svgFile: 'inventarization',
text: 'Инвентаризация',
disable: true,
),
_createDrawerSectionTitle(text: 'СПРАВОЧНИКИ'),
_createDrawerItem(
svgFile: 'categories',
text: 'Категории',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(CategoryDictionaryView));
}),
svgFile: 'categories',
text: 'Категории',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(CategoryDictionaryView));
},
),
_createDrawerItem(
svgFile: 'goods',
text: 'Товары',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(GoodsDictionaryView));
}),
svgFile: 'goods',
text: 'Товары',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(GoodsDictionaryView));
},
),
_createDrawerItem(
svgFile: 'contragents', text: 'Контрагенты', disable: true),
svgFile: 'contragents',
text: 'Контрагенты',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(
navigateDrawer(ContragentsDictionaryView)
);
},
),
_createDrawerSectionTitle(text: 'ИНФОРМАЦИЯ'),
_createDrawerItem(
svgFile: 'question', text: 'Справочник', disable: true),
svgFile: 'question',
text: 'Справочник',
disable: true,
),
_createDrawerSectionTitle(text: 'ПРОЧЕЕ'),
_createDrawerItem(
svgFile: 'settings',
text: 'Настройки',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(SettingsView));
}),
svgFile: 'settings',
text: 'Настройки',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(SettingsView));
},
),
_createDrawerItem(
svgFile: 'global', text: 'Перейти на сайт', disable: true),
svgFile: 'global',
text: 'Перейти на сайт',
disable: true,
),
_createDrawerItem(
svgFile: 'bug', text: 'Сообщить об ошибке', disable: true),
svgFile: 'bug',
text: 'Сообщить об ошибке',
disable: true,
),
_createDrawerItem(
svgFile: 'logout',
text: 'Выйти из аккаунта',
isDanger: true,
onTap: () async {
Redux.store!.dispatch(logout);
}),
svgFile: 'logout',
text: 'Выйти из аккаунта',
isDanger: true,
onTap: () async {
Redux.store!.dispatch(logout);
},
),
_createDrawerSectionTitle(text: ''),
],
),
@ -95,44 +128,60 @@ class AppDrawer extends StatelessWidget {
return SizedBox(
height: 180.h,
child: DrawerHeader(
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage('assets/images/drawer/background.png'))),
child: Stack(children: <Widget>[
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage('assets/images/drawer/background.png'),
),
),
child: Stack(
children: <Widget>[
Positioned(
bottom: 12.0,
left: 16.0,
child: Row(
children: [
SizedBox(
height: 40,
width: 40,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage(
'assets/images/drawer/user.png')))),
bottom: 12.0,
left: 16.0,
child: Row(
children: [
SizedBox(
height: 40,
width: 40,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage(
'assets/images/drawer/user.png',
),
),
),
),
horizontalSpaceSmall,
StoreConnector<AppState, UserState>(
converter: (store) => store.state.userState!,
builder: (context, snapshot) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(snapshot.auth?.username ?? '',
style: TextStyle(fontSize: 16.0)),
Text('Продавец', style: TextStyle(fontSize: 12)),
],
);
}),
],
)),
])),
),
horizontalSpaceSmall,
StoreConnector<AppState, UserState>(
converter: (store) => store.state.userState!,
builder: (context, snapshot) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
snapshot.auth?.username ?? '',
style: const TextStyle(fontSize: 16.0),
),
const Text(
'Продавец',
style: TextStyle(fontSize: 12),
),
],
);
},
),
],
),
),
],
),
),
);
}
@ -148,7 +197,7 @@ class AppDrawer extends StatelessWidget {
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
onTap: disable ? () {} : onTap,
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 15.0, horizontal: 20.0),
@ -180,12 +229,13 @@ class AppDrawer extends StatelessWidget {
child: Text(
text,
style: TextStyle(
fontSize: 14.0,
color: disable
? disableColor
: isDanger
? dangerColor
: textColor),
fontSize: 14.0,
color: disable
? disableColor
: isDanger
? dangerColor
: textColor,
),
),
)
],
@ -198,10 +248,11 @@ class AppDrawer extends StatelessWidget {
Widget _createDrawerSectionTitle({required String text}) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Text(
text,
style: const TextStyle(fontSize: 10.0, color: placeholderColor),
));
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
child: Text(
text,
style: const TextStyle(fontSize: 10.0, color: placeholderColor),
),
);
}
}

View File

@ -1,6 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/shared_styles.dart';
import 'package:satu/shared/ui_helpers.dart';

View File

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'note_text.dart';
class InputCheckBox extends StatelessWidget {
const InputCheckBox(this.text,
{required this.value, this.labelText, this.onChanged});
final String text;
final bool value;
final String? labelText;
final Function(bool? value)? onChanged;
Color getColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.focused,
};
if (states.any(interactiveStates.contains)) {
return Colors.blue;
}
return primaryColor;
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (labelText != null)
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 14.0, vertical: 5.0),
child: NoteText(labelText ?? ''),
),
Container(
decoration: const BoxDecoration(color: whiteColor),
child: Padding(
padding: EdgeInsets.only(left: 5, right: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Checkbox(
value: value,
onChanged: onChanged,
//checkColor: primaryColor,
fillColor: MaterialStateProperty.resolveWith(getColor),
),
Text(
text,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
),
),
],
),
),
),
verticalSpaceSmall
],
);
}
}

View File

@ -8,25 +8,6 @@ import 'package:satu/shared/ui_helpers.dart';
import 'note_text.dart';
class InputField 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;
InputField(
{required this.controller,
@ -48,6 +29,25 @@ class InputField extends StatefulWidget {
this.multiline = false,
this.smallVersion = false,
this.labelText});
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;
@override
_InputFieldState createState() => _InputFieldState();
@ -105,7 +105,7 @@ class _InputFieldState extends State<InputField> {
});
FocusScope.of(context)
.requestFocus(FocusNode()); //remove focus
WidgetsBinding.instance!.addPostFrameCallback(
WidgetsBinding.instance.addPostFrameCallback(
(_) => widget.controller.clear()); // clear content
}
},

View File

@ -8,6 +8,27 @@ import 'package:satu/shared/ui_helpers.dart';
import 'note_text.dart';
class InputFieldRounded extends StatefulWidget {
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});
final TextEditingController controller;
final TextInputType textInputType;
final bool password;
@ -28,27 +49,6 @@ class InputFieldRounded extends StatefulWidget {
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();
}
@ -90,10 +90,12 @@ class _InputFieldRoundedState extends State<InputFieldRounded> {
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
]),
decoration: widget.isReadOnly
? disabledFieldDecoration
: BoxDecoration(
color: whiteColor,
borderRadius: BorderRadius.circular(6.0),
boxShadow: [inputShadowBox]),
child: Row(
children: <Widget>[
GestureDetector(
@ -106,7 +108,7 @@ class _InputFieldRoundedState extends State<InputFieldRounded> {
});
FocusScope.of(context)
.requestFocus(new FocusNode()); //remove focus
WidgetsBinding.instance!.addPostFrameCallback(
WidgetsBinding.instance.addPostFrameCallback(
(_) => widget.controller.clear()); // clear content
}
},
@ -123,9 +125,7 @@ class _InputFieldRoundedState extends State<InputFieldRounded> {
child: TextFormField(
style: TextStyle(
color: textColor,
fontSize: widget.smallVersion
? 12
: 14),
fontSize: widget.smallVersion ? 12 : 14),
controller: widget.controller,
keyboardType: widget.textInputType,
focusNode: widget.fieldFocusNode,

View File

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

View File

@ -1,6 +1,5 @@
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

@ -40,9 +40,7 @@ class _BarcodePermissionWidget extends StatefulWidget {
class _BarcodePermissionWidgetState extends State<_BarcodePermissionWidget> {
bool _isGranted = false;
bool _useCameraScan = true;
String _inputValue = "";
@override
void initState() {

View File

@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/views/work/tabs/component/product_list_item.dart';
class ProductTitleWidget extends StatelessWidget {
const ProductTitleWidget(

View File

@ -175,7 +175,7 @@ packages:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0"
version: "1.16.0"
convert:
dependency: transitive
description:
@ -252,7 +252,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.0"
ffi:
dependency: transitive
description:
@ -286,13 +286,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.7"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
flutter_redux:
dependency: "direct main"
description:
name: flutter_redux
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.2"
version: "0.10.0"
flutter_screenutil:
dependency: "direct main"
description:
@ -358,7 +365,7 @@ packages:
name: grouped_list
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.0"
version: "5.1.2"
hex:
dependency: transitive
description:
@ -408,6 +415,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
infinite_scroll_pagination:
dependency: "direct main"
description:
name: infinite_scroll_pagination
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
intl:
dependency: "direct main"
description:
@ -428,7 +442,7 @@ packages:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3"
version: "0.6.4"
json_annotation:
dependency: transitive
description:
@ -443,13 +457,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.2.0"
lint:
dependency: "direct dev"
lints:
dependency: transitive
description:
name: lint
name: lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
version: "2.0.0"
location_permissions:
dependency: "direct main"
description:
@ -491,7 +505,7 @@ packages:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
version: "0.1.4"
material_design_icons_flutter:
dependency: "direct main"
description:
@ -540,7 +554,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
version: "1.8.1"
path_drawing:
dependency: transitive
description:
@ -805,6 +819,13 @@ packages:
description: flutter
source: sdk
version: "0.0.99"
sliver_tools:
dependency: transitive
description:
name: sliver_tools
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.7"
source_gen:
dependency: transitive
description:
@ -825,7 +846,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
version: "1.8.2"
sqflite:
dependency: "direct main"
description:
@ -888,7 +909,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.8"
version: "0.4.9"
timing:
dependency: transitive
description:
@ -986,7 +1007,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.2"
watcher:
dependency: transitive
description:
@ -1030,5 +1051,5 @@ packages:
source: hosted
version: "3.1.1"
sdks:
dart: ">=2.16.0 <3.0.0"
dart: ">=2.17.3 <3.0.0"
flutter: ">=2.10.0"

View File

@ -17,15 +17,16 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.14.0 <3.0.0"
sdk: ">=2.17.3 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.5
redux: ^5.0.0
flutter_redux: ^0.8.2
flutter_redux: ^0.10.0
redux_thunk: ^0.4.0
redux_persist: ^0.9.0
redux_persist_flutter: ^0.9.0
@ -53,7 +54,8 @@ dependencies:
ai_barcode: ^3.2.0
permission_handler: ^8.3.0
flutter_svg: ^0.23.0+1
grouped_list: ^4.2.0
grouped_list: ^5.1.2
infinite_scroll_pagination: ^3.2.0
flutter_bluetooth_basic: ^0.1.7
location_permissions: ^4.0.1
esc_pos_utils: ^1.1.0
@ -62,9 +64,14 @@ dev_dependencies:
build_runner: ^2.1.5
flutter_test:
sdk: flutter
lint: ^1.7.2
json_serializable: ^6.0.1
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec