Vendors
This commit is contained in:
parent
bfe4d22b7c
commit
b8df45c5a0
|
|
@ -1,6 +1,6 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
|
||||
<configuration default="false" name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter" singleton="false">
|
||||
<option name="filePath" value="$PROJECT_DIR$/lib/main.dart" />
|
||||
<method />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -23,6 +23,8 @@ import 'package:invoiceninja_flutter/redux/ui/ui_state.dart';
|
|||
import 'package:invoiceninja_flutter/redux/invoice/invoice_state.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/task/task_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/project/project_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment/payment_state.dart';
|
||||
|
|
@ -76,6 +78,8 @@ part 'serializers.g.dart';
|
|||
TimezoneItemResponse,
|
||||
TimezoneListResponse,
|
||||
// STARTER: serializers - do not remove comment
|
||||
VendorEntity,
|
||||
|
||||
TaskEntity,
|
||||
ProjectEntity,
|
||||
PaymentEntity,
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
|
|||
..add(VendorEntity.serializer)
|
||||
..add(VendorItemResponse.serializer)
|
||||
..add(VendorListResponse.serializer)
|
||||
..add(VendorState.serializer)
|
||||
..add(VendorUIState.serializer)
|
||||
..addBuilderFactory(
|
||||
const FullType(BuiltList, const [const FullType(ActivityEntity)]),
|
||||
() => new ListBuilder<ActivityEntity>())
|
||||
|
|
@ -363,5 +365,7 @@ Serializers _$serializers = (new Serializers().toBuilder()
|
|||
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(ProjectEntity)]), () => new MapBuilder<int, ProjectEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(int)]), () => new ListBuilder<int>())
|
||||
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(TaskEntity)]), () => new MapBuilder<int, TaskEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(int)]), () => new ListBuilder<int>())
|
||||
..addBuilderFactory(const FullType(BuiltMap, const [const FullType(int), const FullType(VendorEntity)]), () => new MapBuilder<int, VendorEntity>())
|
||||
..addBuilderFactory(const FullType(BuiltList, const [const FullType(int)]), () => new ListBuilder<int>()))
|
||||
.build();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:core';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/constants.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/serializers.dart';
|
||||
import 'package:invoiceninja_flutter/redux/auth/auth_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/data/web_client.dart';
|
||||
|
||||
class VendorRepository {
|
||||
|
||||
const VendorRepository({
|
||||
this.webClient = const WebClient(),
|
||||
});
|
||||
|
||||
final WebClient webClient;
|
||||
|
||||
Future<VendorEntity> loadItem(
|
||||
CompanyEntity company, AuthState auth, int entityId) async {
|
||||
final dynamic response = await webClient.get(
|
||||
'${auth.url}/vendors/$entityId', company.token);
|
||||
|
||||
final VendorItemResponse vendorResponse =
|
||||
serializers.deserializeWith(VendorItemResponse.serializer, response);
|
||||
|
||||
return vendorResponse.data;
|
||||
}
|
||||
|
||||
Future<BuiltList<VendorEntity>> loadList(
|
||||
CompanyEntity company, AuthState auth, int updatedAt) async {
|
||||
String url = auth.url + '/vendors?';
|
||||
|
||||
if (updatedAt > 0) {
|
||||
url += '&updated_at=${updatedAt - kUpdatedAtBufferSeconds}';
|
||||
}
|
||||
|
||||
final dynamic response = await webClient.get(url, company.token);
|
||||
|
||||
final VendorListResponse vendorResponse =
|
||||
serializers.deserializeWith(VendorListResponse.serializer, response);
|
||||
|
||||
return vendorResponse.data;
|
||||
}
|
||||
|
||||
Future<VendorEntity> saveData(
|
||||
CompanyEntity company, AuthState auth, VendorEntity vendor,
|
||||
[EntityAction action]) async {
|
||||
final data = serializers.serializeWith(VendorEntity.serializer, vendor);
|
||||
dynamic response;
|
||||
|
||||
if (vendor.isNew) {
|
||||
response = await webClient.post(
|
||||
auth.url + '/vendors',
|
||||
company.token,
|
||||
json.encode(data));
|
||||
} else {
|
||||
var url = auth.url + '/vendors/' + vendor.id.toString();
|
||||
if (action != null) {
|
||||
url += '?action=' + action.toString();
|
||||
}
|
||||
response = await webClient.put(url, company.token, json.encode(data));
|
||||
}
|
||||
|
||||
final VendorItemResponse vendorResponse =
|
||||
serializers.deserializeWith(VendorItemResponse.serializer, response);
|
||||
|
||||
return vendorResponse.data;
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,12 @@ import 'package:local_auth/local_auth.dart';
|
|||
|
||||
//import 'package:quick_actions/quick_actions.dart';
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/ui/vendor/vendor_screen.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/edit/vendor_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/view/vendor_view_vm.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_middleware.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/ui/task/task_screen.dart';
|
||||
import 'package:invoiceninja_flutter/ui/task/edit/task_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/task/view/task_view_vm.dart';
|
||||
|
|
@ -91,6 +97,8 @@ void main() async {
|
|||
..addAll(createStoreInvoicesMiddleware())
|
||||
..addAll(createStorePersistenceMiddleware())
|
||||
// STARTER: middleware - do not remove comment
|
||||
..addAll(createStoreVendorsMiddleware())
|
||||
|
||||
..addAll(createStoreTasksMiddleware())
|
||||
..addAll(createStoreProjectsMiddleware())
|
||||
..addAll(createStorePaymentsMiddleware())
|
||||
|
|
@ -299,6 +307,13 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
|
|||
InvoiceEditScreen.route: (context) => InvoiceEditScreen(),
|
||||
InvoiceEmailScreen.route: (context) => InvoiceEmailScreen(),
|
||||
// STARTER: routes - do not remove comment
|
||||
VendorScreen.route: (context) {
|
||||
widget.store.dispatch(LoadVendors());
|
||||
return VendorScreen();
|
||||
},
|
||||
VendorViewScreen.route: (context) => VendorViewScreen(),
|
||||
VendorEditScreen.route: (context) => VendorEditScreen(),
|
||||
|
||||
TaskScreen.route: (context) {
|
||||
widget.store.dispatch(LoadTasks());
|
||||
return TaskScreen();
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import 'package:built_value/built_value.dart';
|
|||
import 'package:built_value/serializer.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/task/task_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/project/project_state.dart';
|
||||
|
|
@ -107,6 +109,9 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
|
|||
case EntityType.invoice:
|
||||
return invoiceUIState;
|
||||
// STARTER: states switch - do not remove comment
|
||||
case EntityType.vendor:
|
||||
return vendorUIState;
|
||||
|
||||
case EntityType.task:
|
||||
return taskUIState;
|
||||
|
||||
|
|
@ -145,6 +150,11 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
|
|||
ListUIState get invoiceListState => uiState.invoiceUIState.listUIState;
|
||||
|
||||
// STARTER: state getters - do not remove comment
|
||||
VendorState get vendorState => selectedCompanyState.vendorState;
|
||||
ListUIState get vendorListState => uiState.vendorUIState.listUIState;
|
||||
VendorUIState get vendorUIState => uiState.vendorUIState;
|
||||
|
||||
|
||||
TaskState get taskState => selectedCompanyState.taskState;
|
||||
|
||||
ListUIState get taskListState => uiState.taskUIState.listUIState;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import 'package:invoiceninja_flutter/redux/dashboard/dashboard_reducer.dart';
|
|||
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_reducer.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/task/task_reducer.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/project/project_reducer.dart';
|
||||
|
|
@ -29,6 +31,8 @@ CompanyState companyReducer(CompanyState state, dynamic action) {
|
|||
..productState.replace(productsReducer(state.productState, action))
|
||||
..invoiceState.replace(invoicesReducer(state.invoiceState, action))
|
||||
// STARTER: reducer - do not remove comment
|
||||
..vendorState.replace(vendorsReducer(state.vendorState, action))
|
||||
|
||||
..taskState.replace(tasksReducer(state.taskState, action))
|
||||
..projectState.replace(projectsReducer(state.projectState, action))
|
||||
..paymentState.replace(paymentsReducer(state.paymentState, action))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import 'package:built_value/built_value.dart';
|
|||
import 'package:built_value/serializer.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/task/task_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/project/project_state.dart';
|
||||
|
|
@ -27,6 +29,8 @@ abstract class CompanyState
|
|||
clientState: ClientState(),
|
||||
invoiceState: InvoiceState(),
|
||||
// STARTER: constructor - do not remove comment
|
||||
vendorState: VendorState(),
|
||||
|
||||
taskState: TaskState(),
|
||||
projectState: ProjectState(),
|
||||
paymentState: PaymentState(),
|
||||
|
|
@ -48,6 +52,8 @@ abstract class CompanyState
|
|||
InvoiceState get invoiceState;
|
||||
|
||||
// STARTER: fields - do not remove comment
|
||||
VendorState get vendorState;
|
||||
|
||||
TaskState get taskState;
|
||||
|
||||
ProjectState get projectState;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ class _$CompanyStateSerializer implements StructuredSerializer<CompanyState> {
|
|||
'invoiceState',
|
||||
serializers.serialize(object.invoiceState,
|
||||
specifiedType: const FullType(InvoiceState)),
|
||||
'vendorState',
|
||||
serializers.serialize(object.vendorState,
|
||||
specifiedType: const FullType(VendorState)),
|
||||
'taskState',
|
||||
serializers.serialize(object.taskState,
|
||||
specifiedType: const FullType(TaskState)),
|
||||
|
|
@ -98,6 +101,10 @@ class _$CompanyStateSerializer implements StructuredSerializer<CompanyState> {
|
|||
result.invoiceState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(InvoiceState)) as InvoiceState);
|
||||
break;
|
||||
case 'vendorState':
|
||||
result.vendorState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(VendorState)) as VendorState);
|
||||
break;
|
||||
case 'taskState':
|
||||
result.taskState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(TaskState)) as TaskState);
|
||||
|
|
@ -133,6 +140,8 @@ class _$CompanyState extends CompanyState {
|
|||
@override
|
||||
final InvoiceState invoiceState;
|
||||
@override
|
||||
final VendorState vendorState;
|
||||
@override
|
||||
final TaskState taskState;
|
||||
@override
|
||||
final ProjectState projectState;
|
||||
|
|
@ -150,6 +159,7 @@ class _$CompanyState extends CompanyState {
|
|||
this.productState,
|
||||
this.clientState,
|
||||
this.invoiceState,
|
||||
this.vendorState,
|
||||
this.taskState,
|
||||
this.projectState,
|
||||
this.paymentState,
|
||||
|
|
@ -167,6 +177,9 @@ class _$CompanyState extends CompanyState {
|
|||
if (invoiceState == null) {
|
||||
throw new BuiltValueNullFieldError('CompanyState', 'invoiceState');
|
||||
}
|
||||
if (vendorState == null) {
|
||||
throw new BuiltValueNullFieldError('CompanyState', 'vendorState');
|
||||
}
|
||||
if (taskState == null) {
|
||||
throw new BuiltValueNullFieldError('CompanyState', 'taskState');
|
||||
}
|
||||
|
|
@ -197,6 +210,7 @@ class _$CompanyState extends CompanyState {
|
|||
productState == other.productState &&
|
||||
clientState == other.clientState &&
|
||||
invoiceState == other.invoiceState &&
|
||||
vendorState == other.vendorState &&
|
||||
taskState == other.taskState &&
|
||||
projectState == other.projectState &&
|
||||
paymentState == other.paymentState &&
|
||||
|
|
@ -210,6 +224,7 @@ class _$CompanyState extends CompanyState {
|
|||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc($jc(0, company.hashCode),
|
||||
|
|
@ -217,6 +232,7 @@ class _$CompanyState extends CompanyState {
|
|||
productState.hashCode),
|
||||
clientState.hashCode),
|
||||
invoiceState.hashCode),
|
||||
vendorState.hashCode),
|
||||
taskState.hashCode),
|
||||
projectState.hashCode),
|
||||
paymentState.hashCode),
|
||||
|
|
@ -231,6 +247,7 @@ class _$CompanyState extends CompanyState {
|
|||
..add('productState', productState)
|
||||
..add('clientState', clientState)
|
||||
..add('invoiceState', invoiceState)
|
||||
..add('vendorState', vendorState)
|
||||
..add('taskState', taskState)
|
||||
..add('projectState', projectState)
|
||||
..add('paymentState', paymentState)
|
||||
|
|
@ -272,6 +289,12 @@ class CompanyStateBuilder
|
|||
set invoiceState(InvoiceStateBuilder invoiceState) =>
|
||||
_$this._invoiceState = invoiceState;
|
||||
|
||||
VendorStateBuilder _vendorState;
|
||||
VendorStateBuilder get vendorState =>
|
||||
_$this._vendorState ??= new VendorStateBuilder();
|
||||
set vendorState(VendorStateBuilder vendorState) =>
|
||||
_$this._vendorState = vendorState;
|
||||
|
||||
TaskStateBuilder _taskState;
|
||||
TaskStateBuilder get taskState =>
|
||||
_$this._taskState ??= new TaskStateBuilder();
|
||||
|
|
@ -304,6 +327,7 @@ class CompanyStateBuilder
|
|||
_productState = _$v.productState?.toBuilder();
|
||||
_clientState = _$v.clientState?.toBuilder();
|
||||
_invoiceState = _$v.invoiceState?.toBuilder();
|
||||
_vendorState = _$v.vendorState?.toBuilder();
|
||||
_taskState = _$v.taskState?.toBuilder();
|
||||
_projectState = _$v.projectState?.toBuilder();
|
||||
_paymentState = _$v.paymentState?.toBuilder();
|
||||
|
|
@ -337,6 +361,7 @@ class CompanyStateBuilder
|
|||
productState: productState.build(),
|
||||
clientState: clientState.build(),
|
||||
invoiceState: invoiceState.build(),
|
||||
vendorState: vendorState.build(),
|
||||
taskState: taskState.build(),
|
||||
projectState: projectState.build(),
|
||||
paymentState: paymentState.build(),
|
||||
|
|
@ -354,6 +379,8 @@ class CompanyStateBuilder
|
|||
clientState.build();
|
||||
_$failedField = 'invoiceState';
|
||||
invoiceState.build();
|
||||
_$failedField = 'vendorState';
|
||||
vendorState.build();
|
||||
_$failedField = 'taskState';
|
||||
taskState.build();
|
||||
_$failedField = 'projectState';
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import 'package:invoiceninja_flutter/redux/invoice/invoice_reducer.dart';
|
|||
import 'package:redux/redux.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_reducer.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/task/task_reducer.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/project/project_reducer.dart';
|
||||
|
|
@ -34,6 +36,8 @@ UIState uiReducer(UIState state, dynamic action) {
|
|||
..dashboardUIState
|
||||
.replace(dashboardUIReducer(state.dashboardUIState, action))
|
||||
// STARTER: reducer - do not remove comment
|
||||
..vendorUIState.replace(vendorUIReducer(state.vendorUIState, action))
|
||||
|
||||
..taskUIState.replace(taskUIReducer(state.taskUIState, action))
|
||||
..projectUIState.replace(projectUIReducer(state.projectUIState, action))
|
||||
..paymentUIState.replace(paymentUIReducer(state.paymentUIState, action))
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import 'package:invoiceninja_flutter/redux/product/product_state.dart';
|
|||
import 'package:invoiceninja_flutter/ui/auth/login_vm.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/task/task_state.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/project/project_state.dart';
|
||||
|
|
@ -33,6 +35,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
|
|||
clientUIState: ClientUIState(),
|
||||
invoiceUIState: InvoiceUIState(),
|
||||
// STARTER: constructor - do not remove comment
|
||||
vendorUIState: VendorUIState(),
|
||||
|
||||
taskUIState: TaskUIState(),
|
||||
projectUIState: ProjectUIState(),
|
||||
paymentUIState: PaymentUIState(),
|
||||
|
|
@ -66,6 +70,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
|
|||
String get filter;
|
||||
|
||||
// STARTER: properties - do not remove comment
|
||||
VendorUIState get vendorUIState;
|
||||
|
||||
TaskUIState get taskUIState;
|
||||
|
||||
ProjectUIState get projectUIState;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
|
|||
'invoiceUIState',
|
||||
serializers.serialize(object.invoiceUIState,
|
||||
specifiedType: const FullType(InvoiceUIState)),
|
||||
'vendorUIState',
|
||||
serializers.serialize(object.vendorUIState,
|
||||
specifiedType: const FullType(VendorUIState)),
|
||||
'taskUIState',
|
||||
serializers.serialize(object.taskUIState,
|
||||
specifiedType: const FullType(TaskUIState)),
|
||||
|
|
@ -140,6 +143,10 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
|
|||
result.filter = serializers.deserialize(value,
|
||||
specifiedType: const FullType(String)) as String;
|
||||
break;
|
||||
case 'vendorUIState':
|
||||
result.vendorUIState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(VendorUIState)) as VendorUIState);
|
||||
break;
|
||||
case 'taskUIState':
|
||||
result.taskUIState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(TaskUIState)) as TaskUIState);
|
||||
|
|
@ -187,6 +194,8 @@ class _$UIState extends UIState {
|
|||
@override
|
||||
final String filter;
|
||||
@override
|
||||
final VendorUIState vendorUIState;
|
||||
@override
|
||||
final TaskUIState taskUIState;
|
||||
@override
|
||||
final ProjectUIState projectUIState;
|
||||
|
|
@ -210,6 +219,7 @@ class _$UIState extends UIState {
|
|||
this.clientUIState,
|
||||
this.invoiceUIState,
|
||||
this.filter,
|
||||
this.vendorUIState,
|
||||
this.taskUIState,
|
||||
this.projectUIState,
|
||||
this.paymentUIState,
|
||||
|
|
@ -245,6 +255,9 @@ class _$UIState extends UIState {
|
|||
if (invoiceUIState == null) {
|
||||
throw new BuiltValueNullFieldError('UIState', 'invoiceUIState');
|
||||
}
|
||||
if (vendorUIState == null) {
|
||||
throw new BuiltValueNullFieldError('UIState', 'vendorUIState');
|
||||
}
|
||||
if (taskUIState == null) {
|
||||
throw new BuiltValueNullFieldError('UIState', 'taskUIState');
|
||||
}
|
||||
|
|
@ -281,6 +294,7 @@ class _$UIState extends UIState {
|
|||
clientUIState == other.clientUIState &&
|
||||
invoiceUIState == other.invoiceUIState &&
|
||||
filter == other.filter &&
|
||||
vendorUIState == other.vendorUIState &&
|
||||
taskUIState == other.taskUIState &&
|
||||
projectUIState == other.projectUIState &&
|
||||
paymentUIState == other.paymentUIState &&
|
||||
|
|
@ -302,6 +316,7 @@ class _$UIState extends UIState {
|
|||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
$jc(
|
||||
0,
|
||||
|
|
@ -320,6 +335,7 @@ class _$UIState extends UIState {
|
|||
clientUIState.hashCode),
|
||||
invoiceUIState.hashCode),
|
||||
filter.hashCode),
|
||||
vendorUIState.hashCode),
|
||||
taskUIState.hashCode),
|
||||
projectUIState.hashCode),
|
||||
paymentUIState.hashCode),
|
||||
|
|
@ -340,6 +356,7 @@ class _$UIState extends UIState {
|
|||
..add('clientUIState', clientUIState)
|
||||
..add('invoiceUIState', invoiceUIState)
|
||||
..add('filter', filter)
|
||||
..add('vendorUIState', vendorUIState)
|
||||
..add('taskUIState', taskUIState)
|
||||
..add('projectUIState', projectUIState)
|
||||
..add('paymentUIState', paymentUIState)
|
||||
|
|
@ -407,6 +424,12 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
|
|||
String get filter => _$this._filter;
|
||||
set filter(String filter) => _$this._filter = filter;
|
||||
|
||||
VendorUIStateBuilder _vendorUIState;
|
||||
VendorUIStateBuilder get vendorUIState =>
|
||||
_$this._vendorUIState ??= new VendorUIStateBuilder();
|
||||
set vendorUIState(VendorUIStateBuilder vendorUIState) =>
|
||||
_$this._vendorUIState = vendorUIState;
|
||||
|
||||
TaskUIStateBuilder _taskUIState;
|
||||
TaskUIStateBuilder get taskUIState =>
|
||||
_$this._taskUIState ??= new TaskUIStateBuilder();
|
||||
|
|
@ -446,6 +469,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
|
|||
_clientUIState = _$v.clientUIState?.toBuilder();
|
||||
_invoiceUIState = _$v.invoiceUIState?.toBuilder();
|
||||
_filter = _$v.filter;
|
||||
_vendorUIState = _$v.vendorUIState?.toBuilder();
|
||||
_taskUIState = _$v.taskUIState?.toBuilder();
|
||||
_projectUIState = _$v.projectUIState?.toBuilder();
|
||||
_paymentUIState = _$v.paymentUIState?.toBuilder();
|
||||
|
|
@ -485,6 +509,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
|
|||
clientUIState: clientUIState.build(),
|
||||
invoiceUIState: invoiceUIState.build(),
|
||||
filter: filter,
|
||||
vendorUIState: vendorUIState.build(),
|
||||
taskUIState: taskUIState.build(),
|
||||
projectUIState: projectUIState.build(),
|
||||
paymentUIState: paymentUIState.build(),
|
||||
|
|
@ -501,6 +526,8 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
|
|||
_$failedField = 'invoiceUIState';
|
||||
invoiceUIState.build();
|
||||
|
||||
_$failedField = 'vendorUIState';
|
||||
vendorUIState.build();
|
||||
_$failedField = 'taskUIState';
|
||||
taskUIState.build();
|
||||
_$failedField = 'projectUIState';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,226 @@
|
|||
import 'dart:async';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
|
||||
class ViewVendorList implements PersistUI {
|
||||
ViewVendorList(this.context);
|
||||
|
||||
final BuildContext context;
|
||||
}
|
||||
|
||||
class ViewVendor implements PersistUI {
|
||||
ViewVendor({this.vendorId, this.context});
|
||||
|
||||
final int vendorId;
|
||||
final BuildContext context;
|
||||
}
|
||||
|
||||
class EditVendor implements PersistUI {
|
||||
EditVendor({this.vendor, this.context, this.completer, this.trackRoute = true});
|
||||
|
||||
final VendorEntity vendor;
|
||||
final BuildContext context;
|
||||
final Completer completer;
|
||||
final bool trackRoute;
|
||||
}
|
||||
|
||||
class UpdateVendor implements PersistUI {
|
||||
UpdateVendor(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class LoadVendor {
|
||||
LoadVendor({this.completer, this.vendorId, this.loadActivities = false});
|
||||
|
||||
final Completer completer;
|
||||
final int vendorId;
|
||||
final bool loadActivities;
|
||||
}
|
||||
|
||||
class LoadVendorActivity {
|
||||
LoadVendorActivity({this.completer, this.vendorId});
|
||||
|
||||
final Completer completer;
|
||||
final int vendorId;
|
||||
}
|
||||
|
||||
class LoadVendors {
|
||||
LoadVendors({this.completer, this.force = false});
|
||||
|
||||
final Completer completer;
|
||||
final bool force;
|
||||
}
|
||||
|
||||
class LoadVendorRequest implements StartLoading {}
|
||||
|
||||
class LoadVendorFailure implements StopLoading {
|
||||
LoadVendorFailure(this.error);
|
||||
|
||||
final dynamic error;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoadVendorFailure{error: $error}';
|
||||
}
|
||||
}
|
||||
|
||||
class LoadVendorSuccess implements StopLoading, PersistData {
|
||||
LoadVendorSuccess(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoadVendorSuccess{vendor: $vendor}';
|
||||
}
|
||||
}
|
||||
|
||||
class LoadVendorsRequest implements StartLoading {}
|
||||
|
||||
class LoadVendorsFailure implements StopLoading {
|
||||
LoadVendorsFailure(this.error);
|
||||
|
||||
final dynamic error;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoadVendorsFailure{error: $error}';
|
||||
}
|
||||
}
|
||||
|
||||
class LoadVendorsSuccess implements StopLoading, PersistData {
|
||||
LoadVendorsSuccess(this.vendors);
|
||||
|
||||
final BuiltList<VendorEntity> vendors;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoadVendorsSuccess{vendors: $vendors}';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SaveVendorRequest implements StartSaving {
|
||||
SaveVendorRequest({this.completer, this.vendor});
|
||||
|
||||
final Completer completer;
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class SaveVendorSuccess implements StopSaving, PersistData, PersistUI {
|
||||
SaveVendorSuccess(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class AddVendorSuccess implements StopSaving, PersistData, PersistUI {
|
||||
AddVendorSuccess(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class SaveVendorFailure implements StopSaving {
|
||||
SaveVendorFailure (this.error);
|
||||
|
||||
final Object error;
|
||||
}
|
||||
|
||||
class ArchiveVendorRequest implements StartSaving {
|
||||
ArchiveVendorRequest(this.completer, this.vendorId);
|
||||
|
||||
final Completer completer;
|
||||
final int vendorId;
|
||||
}
|
||||
|
||||
class ArchiveVendorSuccess implements StopSaving, PersistData {
|
||||
ArchiveVendorSuccess(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class ArchiveVendorFailure implements StopSaving {
|
||||
ArchiveVendorFailure(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class DeleteVendorRequest implements StartSaving {
|
||||
DeleteVendorRequest(this.completer, this.vendorId);
|
||||
|
||||
final Completer completer;
|
||||
final int vendorId;
|
||||
}
|
||||
|
||||
class DeleteVendorSuccess implements StopSaving, PersistData {
|
||||
DeleteVendorSuccess(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class DeleteVendorFailure implements StopSaving {
|
||||
DeleteVendorFailure(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class RestoreVendorRequest implements StartSaving {
|
||||
RestoreVendorRequest(this.completer, this.vendorId);
|
||||
|
||||
final Completer completer;
|
||||
final int vendorId;
|
||||
}
|
||||
|
||||
class RestoreVendorSuccess implements StopSaving, PersistData {
|
||||
RestoreVendorSuccess(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
class RestoreVendorFailure implements StopSaving {
|
||||
RestoreVendorFailure(this.vendor);
|
||||
|
||||
final VendorEntity vendor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class FilterVendors {
|
||||
FilterVendors(this.filter);
|
||||
|
||||
final String filter;
|
||||
}
|
||||
|
||||
class SortVendors implements PersistUI {
|
||||
SortVendors(this.field);
|
||||
|
||||
final String field;
|
||||
}
|
||||
|
||||
class FilterVendorsByState implements PersistUI {
|
||||
FilterVendorsByState(this.state);
|
||||
|
||||
final EntityState state;
|
||||
}
|
||||
|
||||
class FilterVendorsByCustom1 implements PersistUI {
|
||||
FilterVendorsByCustom1(this.value);
|
||||
|
||||
final String value;
|
||||
}
|
||||
|
||||
class FilterVendorsByCustom2 implements PersistUI {
|
||||
FilterVendorsByCustom2(this.value);
|
||||
|
||||
final String value;
|
||||
}
|
||||
|
||||
class FilterVendorsByEntity implements PersistUI {
|
||||
FilterVendorsByEntity({this.entityId, this.entityType});
|
||||
|
||||
final int entityId;
|
||||
final EntityType entityType;
|
||||
}
|
||||
|
|
@ -0,0 +1,233 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/vendor_screen.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/edit/vendor_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/view/vendor_view_vm.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/repositories/vendor_repository.dart';
|
||||
|
||||
List<Middleware<AppState>> createStoreVendorsMiddleware([
|
||||
VendorRepository repository = const VendorRepository(),
|
||||
]) {
|
||||
final viewVendorList = _viewVendorList();
|
||||
final viewVendor = _viewVendor();
|
||||
final editVendor = _editVendor();
|
||||
final loadVendors = _loadVendors(repository);
|
||||
final loadVendor = _loadVendor(repository);
|
||||
final saveVendor = _saveVendor(repository);
|
||||
final archiveVendor = _archiveVendor(repository);
|
||||
final deleteVendor = _deleteVendor(repository);
|
||||
final restoreVendor = _restoreVendor(repository);
|
||||
|
||||
return [
|
||||
TypedMiddleware<AppState, ViewVendorList>(viewVendorList),
|
||||
TypedMiddleware<AppState, ViewVendor>(viewVendor),
|
||||
TypedMiddleware<AppState, EditVendor>(editVendor),
|
||||
TypedMiddleware<AppState, LoadVendors>(loadVendors),
|
||||
TypedMiddleware<AppState, LoadVendor>(loadVendor),
|
||||
TypedMiddleware<AppState, SaveVendorRequest>(saveVendor),
|
||||
TypedMiddleware<AppState, ArchiveVendorRequest>(archiveVendor),
|
||||
TypedMiddleware<AppState, DeleteVendorRequest>(deleteVendor),
|
||||
TypedMiddleware<AppState, RestoreVendorRequest>(restoreVendor),
|
||||
];
|
||||
}
|
||||
|
||||
Middleware<AppState> _editVendor() {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) async {
|
||||
next(action);
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(VendorEditScreen.route));
|
||||
final vendor =
|
||||
await Navigator.of(action.context).pushNamed(VendorEditScreen.route);
|
||||
|
||||
if (action.completer != null && vendor != null) {
|
||||
action.completer.complete(vendor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _viewVendor() {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) async {
|
||||
next(action);
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(VendorViewScreen.route));
|
||||
Navigator.of(action.context).pushNamed(VendorViewScreen.route);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _viewVendorList() {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||
next(action);
|
||||
|
||||
store.dispatch(UpdateCurrentRoute(VendorScreen.route));
|
||||
|
||||
Navigator.of(action.context).pushNamedAndRemoveUntil(VendorScreen.route, (Route<dynamic> route) => false);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _archiveVendor(VendorRepository repository) {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||
final origVendor = store.state.vendorState.map[action.vendorId];
|
||||
repository
|
||||
.saveData(store.state.selectedCompany, store.state.authState,
|
||||
origVendor, EntityAction.archive)
|
||||
.then((VendorEntity vendor) {
|
||||
store.dispatch(ArchiveVendorSuccess(vendor));
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(ArchiveVendorFailure(origVendor));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _deleteVendor(VendorRepository repository) {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||
final origVendor = store.state.vendorState.map[action.vendorId];
|
||||
repository
|
||||
.saveData(store.state.selectedCompany, store.state.authState,
|
||||
origVendor, EntityAction.delete)
|
||||
.then((VendorEntity vendor) {
|
||||
store.dispatch(DeleteVendorSuccess(vendor));
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(DeleteVendorFailure(origVendor));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _restoreVendor(VendorRepository repository) {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||
final origVendor = store.state.vendorState.map[action.vendorId];
|
||||
repository
|
||||
.saveData(store.state.selectedCompany, store.state.authState,
|
||||
origVendor, EntityAction.restore)
|
||||
.then((VendorEntity vendor) {
|
||||
store.dispatch(RestoreVendorSuccess(vendor));
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(RestoreVendorFailure(origVendor));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _saveVendor(VendorRepository repository) {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||
repository
|
||||
.saveData(
|
||||
store.state.selectedCompany, store.state.authState, action.vendor)
|
||||
.then((VendorEntity vendor) {
|
||||
if (action.vendor.isNew) {
|
||||
store.dispatch(AddVendorSuccess(vendor));
|
||||
} else {
|
||||
store.dispatch(SaveVendorSuccess(vendor));
|
||||
}
|
||||
action.completer.complete(vendor);
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(SaveVendorFailure(error));
|
||||
action.completer.completeError(error);
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _loadVendor(VendorRepository repository) {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||
final AppState state = store.state;
|
||||
|
||||
if (state.isLoading) {
|
||||
next(action);
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(LoadVendorRequest());
|
||||
repository
|
||||
.loadItem(state.selectedCompany, state.authState, action.vendorId)
|
||||
.then((vendor) {
|
||||
store.dispatch(LoadVendorSuccess(vendor));
|
||||
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(LoadVendorFailure(error));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
||||
Middleware<AppState> _loadVendors(VendorRepository repository) {
|
||||
return (Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||
final AppState state = store.state;
|
||||
|
||||
if (!state.vendorState.isStale && !action.force) {
|
||||
next(action);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.isLoading) {
|
||||
next(action);
|
||||
return;
|
||||
}
|
||||
|
||||
final int updatedAt = (state.vendorState.lastUpdated / 1000).round();
|
||||
|
||||
store.dispatch(LoadVendorsRequest());
|
||||
repository
|
||||
.loadList(state.selectedCompany, state.authState, updatedAt)
|
||||
.then((data) {
|
||||
store.dispatch(LoadVendorsSuccess(data));
|
||||
|
||||
if (action.completer != null) {
|
||||
action.completer.complete(null);
|
||||
}
|
||||
/*
|
||||
if (state.productState.isStale) {
|
||||
store.dispatch(LoadProducts());
|
||||
}
|
||||
*/
|
||||
}).catchError((Object error) {
|
||||
print(error);
|
||||
store.dispatch(LoadVendorsFailure(error));
|
||||
if (action.completer != null) {
|
||||
action.completer.completeError(error);
|
||||
}
|
||||
});
|
||||
|
||||
next(action);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
import 'package:redux/redux.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_state.dart';
|
||||
|
||||
EntityUIState vendorUIReducer(VendorUIState state, dynamic action) {
|
||||
return state.rebuild((b) => b
|
||||
..listUIState.replace(vendorListReducer(state.listUIState, action))
|
||||
..editing.replace(editingReducer(state.editing, action))
|
||||
..selectedId = selectedIdReducer(state.selectedId, action));
|
||||
}
|
||||
|
||||
Reducer<int> selectedIdReducer = combineReducers([
|
||||
TypedReducer<int, ViewVendor>(
|
||||
(int selectedId, dynamic action) => action.vendorId),
|
||||
TypedReducer<int, AddVendorSuccess>(
|
||||
(int selectedId, dynamic action) => action.vendor.id),
|
||||
]);
|
||||
|
||||
final editingReducer = combineReducers<VendorEntity>([
|
||||
TypedReducer<VendorEntity, SaveVendorSuccess>(_updateEditing),
|
||||
TypedReducer<VendorEntity, AddVendorSuccess>(_updateEditing),
|
||||
TypedReducer<VendorEntity, RestoreVendorSuccess>(_updateEditing),
|
||||
TypedReducer<VendorEntity, ArchiveVendorSuccess>(_updateEditing),
|
||||
TypedReducer<VendorEntity, DeleteVendorSuccess>(_updateEditing),
|
||||
TypedReducer<VendorEntity, EditVendor>(_updateEditing),
|
||||
TypedReducer<VendorEntity, UpdateVendor>(_updateEditing),
|
||||
TypedReducer<VendorEntity, SelectCompany>(_clearEditing),
|
||||
]);
|
||||
|
||||
VendorEntity _clearEditing(VendorEntity vendor, dynamic action) {
|
||||
return VendorEntity();
|
||||
}
|
||||
|
||||
VendorEntity _updateEditing(VendorEntity vendor, dynamic action) {
|
||||
return action.vendor;
|
||||
}
|
||||
|
||||
|
||||
final vendorListReducer = combineReducers<ListUIState>([
|
||||
TypedReducer<ListUIState, SortVendors>(_sortVendors),
|
||||
TypedReducer<ListUIState, FilterVendorsByState>(_filterVendorsByState),
|
||||
TypedReducer<ListUIState, FilterVendors>(_filterVendors),
|
||||
TypedReducer<ListUIState, FilterVendorsByCustom1>(_filterVendorsByCustom1),
|
||||
TypedReducer<ListUIState, FilterVendorsByCustom2>(_filterVendorsByCustom2),
|
||||
TypedReducer<ListUIState, FilterVendorsByEntity>(_filterVendorsByClient),
|
||||
]);
|
||||
|
||||
ListUIState _filterVendorsByClient(
|
||||
ListUIState vendorListState, FilterVendorsByEntity action) {
|
||||
return vendorListState.rebuild((b) => b
|
||||
..filterEntityId = action.entityId
|
||||
..filterEntityType = action.entityType);
|
||||
}
|
||||
|
||||
ListUIState _filterVendorsByCustom1(
|
||||
ListUIState vendorListState, FilterVendorsByCustom1 action) {
|
||||
if (vendorListState.custom1Filters.contains(action.value)) {
|
||||
return vendorListState
|
||||
.rebuild((b) => b..custom1Filters.remove(action.value));
|
||||
} else {
|
||||
return vendorListState.rebuild((b) => b..custom1Filters.add(action.value));
|
||||
}
|
||||
}
|
||||
|
||||
ListUIState _filterVendorsByCustom2(
|
||||
ListUIState vendorListState, FilterVendorsByCustom2 action) {
|
||||
if (vendorListState.custom2Filters.contains(action.value)) {
|
||||
return vendorListState
|
||||
.rebuild((b) => b..custom2Filters.remove(action.value));
|
||||
} else {
|
||||
return vendorListState.rebuild((b) => b..custom2Filters.add(action.value));
|
||||
}
|
||||
}
|
||||
|
||||
ListUIState _filterVendorsByState(
|
||||
ListUIState vendorListState, FilterVendorsByState action) {
|
||||
if (vendorListState.stateFilters.contains(action.state)) {
|
||||
return vendorListState.rebuild((b) => b..stateFilters.remove(action.state));
|
||||
} else {
|
||||
return vendorListState.rebuild((b) => b..stateFilters.add(action.state));
|
||||
}
|
||||
}
|
||||
|
||||
ListUIState _filterVendors(ListUIState vendorListState, FilterVendors action) {
|
||||
return vendorListState.rebuild((b) => b..filter = action.filter);
|
||||
}
|
||||
|
||||
ListUIState _sortVendors(ListUIState vendorListState, SortVendors action) {
|
||||
return vendorListState.rebuild((b) => b
|
||||
..sortAscending = b.sortField != action.field || !b.sortAscending
|
||||
..sortField = action.field);
|
||||
}
|
||||
|
||||
final vendorsReducer = combineReducers<VendorState>([
|
||||
TypedReducer<VendorState, SaveVendorSuccess>(_updateVendor),
|
||||
TypedReducer<VendorState, AddVendorSuccess>(_addVendor),
|
||||
TypedReducer<VendorState, LoadVendorsSuccess>(_setLoadedVendors),
|
||||
TypedReducer<VendorState, LoadVendorSuccess>(_setLoadedVendor),
|
||||
TypedReducer<VendorState, ArchiveVendorRequest>(_archiveVendorRequest),
|
||||
TypedReducer<VendorState, ArchiveVendorSuccess>(_archiveVendorSuccess),
|
||||
TypedReducer<VendorState, ArchiveVendorFailure>(_archiveVendorFailure),
|
||||
TypedReducer<VendorState, DeleteVendorRequest>(_deleteVendorRequest),
|
||||
TypedReducer<VendorState, DeleteVendorSuccess>(_deleteVendorSuccess),
|
||||
TypedReducer<VendorState, DeleteVendorFailure>(_deleteVendorFailure),
|
||||
TypedReducer<VendorState, RestoreVendorRequest>(_restoreVendorRequest),
|
||||
TypedReducer<VendorState, RestoreVendorSuccess>(_restoreVendorSuccess),
|
||||
TypedReducer<VendorState, RestoreVendorFailure>(_restoreVendorFailure),
|
||||
]);
|
||||
|
||||
VendorState _archiveVendorRequest(
|
||||
VendorState vendorState, ArchiveVendorRequest action) {
|
||||
final vendor = vendorState.map[action.vendorId]
|
||||
.rebuild((b) => b..archivedAt = DateTime.now().millisecondsSinceEpoch);
|
||||
|
||||
return vendorState.rebuild((b) => b..map[action.vendorId] = vendor);
|
||||
}
|
||||
|
||||
VendorState _archiveVendorSuccess(
|
||||
VendorState vendorState, ArchiveVendorSuccess action) {
|
||||
return vendorState.rebuild((b) => b..map[action.vendor.id] = action.vendor);
|
||||
}
|
||||
|
||||
VendorState _archiveVendorFailure(
|
||||
VendorState vendorState, ArchiveVendorFailure action) {
|
||||
return vendorState.rebuild((b) => b..map[action.vendor.id] = action.vendor);
|
||||
}
|
||||
|
||||
VendorState _deleteVendorRequest(
|
||||
VendorState vendorState, DeleteVendorRequest action) {
|
||||
final vendor = vendorState.map[action.vendorId].rebuild((b) => b
|
||||
..archivedAt = DateTime.now().millisecondsSinceEpoch
|
||||
..isDeleted = true);
|
||||
|
||||
return vendorState.rebuild((b) => b..map[action.vendorId] = vendor);
|
||||
}
|
||||
|
||||
VendorState _deleteVendorSuccess(
|
||||
VendorState vendorState, DeleteVendorSuccess action) {
|
||||
return vendorState.rebuild((b) => b..map[action.vendor.id] = action.vendor);
|
||||
}
|
||||
|
||||
VendorState _deleteVendorFailure(
|
||||
VendorState vendorState, DeleteVendorFailure action) {
|
||||
return vendorState.rebuild((b) => b..map[action.vendor.id] = action.vendor);
|
||||
}
|
||||
|
||||
VendorState _restoreVendorRequest(
|
||||
VendorState vendorState, RestoreVendorRequest action) {
|
||||
final vendor = vendorState.map[action.vendorId].rebuild((b) => b
|
||||
..archivedAt = null
|
||||
..isDeleted = false);
|
||||
return vendorState.rebuild((b) => b..map[action.vendorId] = vendor);
|
||||
}
|
||||
|
||||
VendorState _restoreVendorSuccess(
|
||||
VendorState vendorState, RestoreVendorSuccess action) {
|
||||
return vendorState.rebuild((b) => b..map[action.vendor.id] = action.vendor);
|
||||
}
|
||||
|
||||
VendorState _restoreVendorFailure(
|
||||
VendorState vendorState, RestoreVendorFailure action) {
|
||||
return vendorState.rebuild((b) => b..map[action.vendor.id] = action.vendor);
|
||||
}
|
||||
|
||||
VendorState _addVendor(VendorState vendorState, AddVendorSuccess action) {
|
||||
return vendorState.rebuild((b) => b
|
||||
..map[action.vendor.id] = action.vendor
|
||||
..list.add(action.vendor.id));
|
||||
}
|
||||
|
||||
VendorState _updateVendor(VendorState vendorState, SaveVendorSuccess action) {
|
||||
return vendorState.rebuild((b) => b
|
||||
..map[action.vendor.id] = action.vendor);
|
||||
}
|
||||
|
||||
VendorState _setLoadedVendor(
|
||||
VendorState vendorState, LoadVendorSuccess action) {
|
||||
return vendorState.rebuild((b) => b
|
||||
..map[action.vendor.id] = action.vendor);
|
||||
}
|
||||
|
||||
VendorState _setLoadedVendors(
|
||||
VendorState vendorState, LoadVendorsSuccess action) {
|
||||
final state = vendorState.rebuild((b) => b
|
||||
..lastUpdated = DateTime.now().millisecondsSinceEpoch
|
||||
..map.addAll(Map.fromIterable(
|
||||
action.vendors,
|
||||
key: (dynamic item) => item.id,
|
||||
value: (dynamic item) => item,
|
||||
)));
|
||||
|
||||
return state.rebuild((b) => b..list.replace(state.map.keys));
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
import 'package:memoize/memoize.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
|
||||
var memoizedDropdownVendorList = memo3(
|
||||
(BuiltMap<int, VendorEntity> vendorMap, BuiltList<int> vendorList,
|
||||
int clientId) =>
|
||||
dropdownVendorsSelector(vendorMap, vendorList, clientId));
|
||||
|
||||
List<int> dropdownVendorsSelector(BuiltMap<int, VendorEntity> vendorMap,
|
||||
BuiltList<int> vendorList, int clientId) {
|
||||
final list = vendorList.where((vendorId) {
|
||||
final vendor = vendorMap[vendorId];
|
||||
/*
|
||||
if (clientId != null && clientId > 0 && vendor.clientId != clientId) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return vendor.isActive;
|
||||
}).toList();
|
||||
|
||||
list.sort((vendorAId, vendorBId) {
|
||||
final vendorA = vendorMap[vendorAId];
|
||||
final vendorB = vendorMap[vendorBId];
|
||||
return vendorA.compareTo(vendorB, VendorFields.name, true);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
var memoizedFilteredVendorList = memo3((BuiltMap<int, VendorEntity> vendorMap,
|
||||
BuiltList<int> vendorList, ListUIState vendorListState) =>
|
||||
filteredVendorsSelector(vendorMap, vendorList, vendorListState));
|
||||
|
||||
List<int> filteredVendorsSelector(BuiltMap<int, VendorEntity> vendorMap,
|
||||
BuiltList<int> vendorList, ListUIState vendorListState) {
|
||||
final list = vendorList.where((vendorId) {
|
||||
final vendor = vendorMap[vendorId];
|
||||
if (!vendor.matchesStates(vendorListState.stateFilters)) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
if (vendorListState.filterEntityId != null &&
|
||||
vendor.clientId != vendorListState.filterEntityId) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
if (vendorListState.custom1Filters.isNotEmpty &&
|
||||
!vendorListState.custom1Filters.contains(vendor.customValue1)) {
|
||||
return false;
|
||||
}
|
||||
if (vendorListState.custom2Filters.isNotEmpty &&
|
||||
!vendorListState.custom2Filters.contains(vendor.customValue2)) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
if (vendorListState.filterEntityId != null &&
|
||||
vendor.entityId != vendorListState.filterEntityId) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return vendor.matchesFilter(vendorListState.filter);
|
||||
}).toList();
|
||||
|
||||
list.sort((vendorAId, vendorBId) {
|
||||
final vendorA = vendorMap[vendorAId];
|
||||
final vendorB = vendorMap[vendorBId];
|
||||
return vendorA.compareTo(
|
||||
vendorB, vendorListState.sortField, vendorListState.sortAscending);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
import 'package:built_value/built_value.dart';
|
||||
import 'package:built_value/serializer.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/constants.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/vendor_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
|
||||
part 'vendor_state.g.dart';
|
||||
|
||||
abstract class VendorState implements Built<VendorState, VendorStateBuilder> {
|
||||
|
||||
factory VendorState() {
|
||||
return _$VendorState._(
|
||||
lastUpdated: 0,
|
||||
map: BuiltMap<int, VendorEntity>(),
|
||||
list: BuiltList<int>(),
|
||||
);
|
||||
}
|
||||
VendorState._();
|
||||
|
||||
@nullable
|
||||
int get lastUpdated;
|
||||
|
||||
BuiltMap<int, VendorEntity> get map;
|
||||
BuiltList<int> get list;
|
||||
|
||||
bool get isStale {
|
||||
if (! isLoaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return DateTime.now().millisecondsSinceEpoch - lastUpdated > kMillisecondsToRefreshData;
|
||||
}
|
||||
|
||||
bool get isLoaded => lastUpdated != null && lastUpdated > 0;
|
||||
|
||||
static Serializer<VendorState> get serializer => _$vendorStateSerializer;
|
||||
}
|
||||
|
||||
abstract class VendorUIState extends Object with EntityUIState implements Built<VendorUIState, VendorUIStateBuilder> {
|
||||
|
||||
factory VendorUIState() {
|
||||
return _$VendorUIState._(
|
||||
listUIState: ListUIState(VendorFields.name),
|
||||
editing: VendorEntity(),
|
||||
selectedId: 0,
|
||||
);
|
||||
}
|
||||
VendorUIState._();
|
||||
|
||||
@nullable
|
||||
VendorEntity get editing;
|
||||
|
||||
@override
|
||||
bool get isCreatingNew => editing.isNew;
|
||||
|
||||
static Serializer<VendorUIState> get serializer => _$vendorUIStateSerializer;
|
||||
}
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'vendor_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// BuiltValueGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// ignore_for_file: always_put_control_body_on_new_line
|
||||
// ignore_for_file: annotate_overrides
|
||||
// ignore_for_file: avoid_annotating_with_dynamic
|
||||
// ignore_for_file: avoid_catches_without_on_clauses
|
||||
// ignore_for_file: avoid_returning_this
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
// ignore_for_file: omit_local_variable_types
|
||||
// ignore_for_file: prefer_expression_function_bodies
|
||||
// ignore_for_file: sort_constructors_first
|
||||
// ignore_for_file: unnecessary_const
|
||||
// ignore_for_file: unnecessary_new
|
||||
// ignore_for_file: test_types_in_equals
|
||||
|
||||
Serializer<VendorState> _$vendorStateSerializer = new _$VendorStateSerializer();
|
||||
Serializer<VendorUIState> _$vendorUIStateSerializer =
|
||||
new _$VendorUIStateSerializer();
|
||||
|
||||
class _$VendorStateSerializer implements StructuredSerializer<VendorState> {
|
||||
@override
|
||||
final Iterable<Type> types = const [VendorState, _$VendorState];
|
||||
@override
|
||||
final String wireName = 'VendorState';
|
||||
|
||||
@override
|
||||
Iterable serialize(Serializers serializers, VendorState object,
|
||||
{FullType specifiedType = FullType.unspecified}) {
|
||||
final result = <Object>[
|
||||
'map',
|
||||
serializers.serialize(object.map,
|
||||
specifiedType: const FullType(BuiltMap,
|
||||
const [const FullType(int), const FullType(VendorEntity)])),
|
||||
'list',
|
||||
serializers.serialize(object.list,
|
||||
specifiedType:
|
||||
const FullType(BuiltList, const [const FullType(int)])),
|
||||
];
|
||||
if (object.lastUpdated != null) {
|
||||
result
|
||||
..add('lastUpdated')
|
||||
..add(serializers.serialize(object.lastUpdated,
|
||||
specifiedType: const FullType(int)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
VendorState deserialize(Serializers serializers, Iterable serialized,
|
||||
{FullType specifiedType = FullType.unspecified}) {
|
||||
final result = new VendorStateBuilder();
|
||||
|
||||
final iterator = serialized.iterator;
|
||||
while (iterator.moveNext()) {
|
||||
final key = iterator.current as String;
|
||||
iterator.moveNext();
|
||||
final dynamic value = iterator.current;
|
||||
switch (key) {
|
||||
case 'lastUpdated':
|
||||
result.lastUpdated = serializers.deserialize(value,
|
||||
specifiedType: const FullType(int)) as int;
|
||||
break;
|
||||
case 'map':
|
||||
result.map.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(BuiltMap, const [
|
||||
const FullType(int),
|
||||
const FullType(VendorEntity)
|
||||
])) as BuiltMap);
|
||||
break;
|
||||
case 'list':
|
||||
result.list.replace(serializers.deserialize(value,
|
||||
specifiedType:
|
||||
const FullType(BuiltList, const [const FullType(int)]))
|
||||
as BuiltList);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result.build();
|
||||
}
|
||||
}
|
||||
|
||||
class _$VendorUIStateSerializer implements StructuredSerializer<VendorUIState> {
|
||||
@override
|
||||
final Iterable<Type> types = const [VendorUIState, _$VendorUIState];
|
||||
@override
|
||||
final String wireName = 'VendorUIState';
|
||||
|
||||
@override
|
||||
Iterable serialize(Serializers serializers, VendorUIState object,
|
||||
{FullType specifiedType = FullType.unspecified}) {
|
||||
final result = <Object>[
|
||||
'selectedId',
|
||||
serializers.serialize(object.selectedId,
|
||||
specifiedType: const FullType(int)),
|
||||
'listUIState',
|
||||
serializers.serialize(object.listUIState,
|
||||
specifiedType: const FullType(ListUIState)),
|
||||
];
|
||||
if (object.editing != null) {
|
||||
result
|
||||
..add('editing')
|
||||
..add(serializers.serialize(object.editing,
|
||||
specifiedType: const FullType(VendorEntity)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
VendorUIState deserialize(Serializers serializers, Iterable serialized,
|
||||
{FullType specifiedType = FullType.unspecified}) {
|
||||
final result = new VendorUIStateBuilder();
|
||||
|
||||
final iterator = serialized.iterator;
|
||||
while (iterator.moveNext()) {
|
||||
final key = iterator.current as String;
|
||||
iterator.moveNext();
|
||||
final dynamic value = iterator.current;
|
||||
switch (key) {
|
||||
case 'editing':
|
||||
result.editing.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(VendorEntity)) as VendorEntity);
|
||||
break;
|
||||
case 'selectedId':
|
||||
result.selectedId = serializers.deserialize(value,
|
||||
specifiedType: const FullType(int)) as int;
|
||||
break;
|
||||
case 'listUIState':
|
||||
result.listUIState.replace(serializers.deserialize(value,
|
||||
specifiedType: const FullType(ListUIState)) as ListUIState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result.build();
|
||||
}
|
||||
}
|
||||
|
||||
class _$VendorState extends VendorState {
|
||||
@override
|
||||
final int lastUpdated;
|
||||
@override
|
||||
final BuiltMap<int, VendorEntity> map;
|
||||
@override
|
||||
final BuiltList<int> list;
|
||||
|
||||
factory _$VendorState([void updates(VendorStateBuilder b)]) =>
|
||||
(new VendorStateBuilder()..update(updates)).build();
|
||||
|
||||
_$VendorState._({this.lastUpdated, this.map, this.list}) : super._() {
|
||||
if (map == null) {
|
||||
throw new BuiltValueNullFieldError('VendorState', 'map');
|
||||
}
|
||||
if (list == null) {
|
||||
throw new BuiltValueNullFieldError('VendorState', 'list');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
VendorState rebuild(void updates(VendorStateBuilder b)) =>
|
||||
(toBuilder()..update(updates)).build();
|
||||
|
||||
@override
|
||||
VendorStateBuilder toBuilder() => new VendorStateBuilder()..replace(this);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(other, this)) return true;
|
||||
return other is VendorState &&
|
||||
lastUpdated == other.lastUpdated &&
|
||||
map == other.map &&
|
||||
list == other.list;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return $jf(
|
||||
$jc($jc($jc(0, lastUpdated.hashCode), map.hashCode), list.hashCode));
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (newBuiltValueToStringHelper('VendorState')
|
||||
..add('lastUpdated', lastUpdated)
|
||||
..add('map', map)
|
||||
..add('list', list))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class VendorStateBuilder implements Builder<VendorState, VendorStateBuilder> {
|
||||
_$VendorState _$v;
|
||||
|
||||
int _lastUpdated;
|
||||
int get lastUpdated => _$this._lastUpdated;
|
||||
set lastUpdated(int lastUpdated) => _$this._lastUpdated = lastUpdated;
|
||||
|
||||
MapBuilder<int, VendorEntity> _map;
|
||||
MapBuilder<int, VendorEntity> get map =>
|
||||
_$this._map ??= new MapBuilder<int, VendorEntity>();
|
||||
set map(MapBuilder<int, VendorEntity> map) => _$this._map = map;
|
||||
|
||||
ListBuilder<int> _list;
|
||||
ListBuilder<int> get list => _$this._list ??= new ListBuilder<int>();
|
||||
set list(ListBuilder<int> list) => _$this._list = list;
|
||||
|
||||
VendorStateBuilder();
|
||||
|
||||
VendorStateBuilder get _$this {
|
||||
if (_$v != null) {
|
||||
_lastUpdated = _$v.lastUpdated;
|
||||
_map = _$v.map?.toBuilder();
|
||||
_list = _$v.list?.toBuilder();
|
||||
_$v = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@override
|
||||
void replace(VendorState other) {
|
||||
if (other == null) {
|
||||
throw new ArgumentError.notNull('other');
|
||||
}
|
||||
_$v = other as _$VendorState;
|
||||
}
|
||||
|
||||
@override
|
||||
void update(void updates(VendorStateBuilder b)) {
|
||||
if (updates != null) updates(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_$VendorState build() {
|
||||
_$VendorState _$result;
|
||||
try {
|
||||
_$result = _$v ??
|
||||
new _$VendorState._(
|
||||
lastUpdated: lastUpdated, map: map.build(), list: list.build());
|
||||
} catch (_) {
|
||||
String _$failedField;
|
||||
try {
|
||||
_$failedField = 'map';
|
||||
map.build();
|
||||
_$failedField = 'list';
|
||||
list.build();
|
||||
} catch (e) {
|
||||
throw new BuiltValueNestedFieldError(
|
||||
'VendorState', _$failedField, e.toString());
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
replace(_$result);
|
||||
return _$result;
|
||||
}
|
||||
}
|
||||
|
||||
class _$VendorUIState extends VendorUIState {
|
||||
@override
|
||||
final VendorEntity editing;
|
||||
@override
|
||||
final int selectedId;
|
||||
@override
|
||||
final ListUIState listUIState;
|
||||
|
||||
factory _$VendorUIState([void updates(VendorUIStateBuilder b)]) =>
|
||||
(new VendorUIStateBuilder()..update(updates)).build();
|
||||
|
||||
_$VendorUIState._({this.editing, this.selectedId, this.listUIState})
|
||||
: super._() {
|
||||
if (selectedId == null) {
|
||||
throw new BuiltValueNullFieldError('VendorUIState', 'selectedId');
|
||||
}
|
||||
if (listUIState == null) {
|
||||
throw new BuiltValueNullFieldError('VendorUIState', 'listUIState');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
VendorUIState rebuild(void updates(VendorUIStateBuilder b)) =>
|
||||
(toBuilder()..update(updates)).build();
|
||||
|
||||
@override
|
||||
VendorUIStateBuilder toBuilder() => new VendorUIStateBuilder()..replace(this);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(other, this)) return true;
|
||||
return other is VendorUIState &&
|
||||
editing == other.editing &&
|
||||
selectedId == other.selectedId &&
|
||||
listUIState == other.listUIState;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return $jf($jc($jc($jc(0, editing.hashCode), selectedId.hashCode),
|
||||
listUIState.hashCode));
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (newBuiltValueToStringHelper('VendorUIState')
|
||||
..add('editing', editing)
|
||||
..add('selectedId', selectedId)
|
||||
..add('listUIState', listUIState))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class VendorUIStateBuilder
|
||||
implements Builder<VendorUIState, VendorUIStateBuilder> {
|
||||
_$VendorUIState _$v;
|
||||
|
||||
VendorEntityBuilder _editing;
|
||||
VendorEntityBuilder get editing =>
|
||||
_$this._editing ??= new VendorEntityBuilder();
|
||||
set editing(VendorEntityBuilder editing) => _$this._editing = editing;
|
||||
|
||||
int _selectedId;
|
||||
int get selectedId => _$this._selectedId;
|
||||
set selectedId(int selectedId) => _$this._selectedId = selectedId;
|
||||
|
||||
ListUIStateBuilder _listUIState;
|
||||
ListUIStateBuilder get listUIState =>
|
||||
_$this._listUIState ??= new ListUIStateBuilder();
|
||||
set listUIState(ListUIStateBuilder listUIState) =>
|
||||
_$this._listUIState = listUIState;
|
||||
|
||||
VendorUIStateBuilder();
|
||||
|
||||
VendorUIStateBuilder get _$this {
|
||||
if (_$v != null) {
|
||||
_editing = _$v.editing?.toBuilder();
|
||||
_selectedId = _$v.selectedId;
|
||||
_listUIState = _$v.listUIState?.toBuilder();
|
||||
_$v = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@override
|
||||
void replace(VendorUIState other) {
|
||||
if (other == null) {
|
||||
throw new ArgumentError.notNull('other');
|
||||
}
|
||||
_$v = other as _$VendorUIState;
|
||||
}
|
||||
|
||||
@override
|
||||
void update(void updates(VendorUIStateBuilder b)) {
|
||||
if (updates != null) updates(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_$VendorUIState build() {
|
||||
_$VendorUIState _$result;
|
||||
try {
|
||||
_$result = _$v ??
|
||||
new _$VendorUIState._(
|
||||
editing: _editing?.build(),
|
||||
selectedId: selectedId,
|
||||
listUIState: listUIState.build());
|
||||
} catch (_) {
|
||||
String _$failedField;
|
||||
try {
|
||||
_$failedField = 'editing';
|
||||
_editing?.build();
|
||||
|
||||
_$failedField = 'listUIState';
|
||||
listUIState.build();
|
||||
} catch (e) {
|
||||
throw new BuiltValueNestedFieldError(
|
||||
'VendorUIState', _$failedField, e.toString());
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
replace(_$result);
|
||||
return _$result;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@ import 'package:redux/redux.dart';
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
|
||||
// STARTER: import - do not remove comment
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
|
||||
import 'package:invoiceninja_flutter/redux/task/task_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/project/project_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/payment/payment_actions.dart';
|
||||
|
|
@ -213,7 +215,6 @@ class AppDrawer extends StatelessWidget {
|
|||
quote: InvoiceEntity(isQuote: true), context: context));
|
||||
},
|
||||
),
|
||||
// STARTER: menu - do not remove comment
|
||||
DrawerTile(
|
||||
company: company,
|
||||
entityType: EntityType.project,
|
||||
|
|
@ -239,45 +240,19 @@ class AppDrawer extends StatelessWidget {
|
|||
context: context));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
leading: Icon(FontAwesomeIcons.building, size: 22.0),
|
||||
title: Text('Vendors & Expenses'),
|
||||
onTap: () {
|
||||
showDialog<AlertDialog>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
semanticLabel: 'Vendors & Expenses',
|
||||
title: Text('Vendors & Expenses'),
|
||||
content: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
style: aboutTextStyle,
|
||||
text: localization.thanksForPatience + ' ',
|
||||
),
|
||||
_LinkTextSpan(
|
||||
style: linkStyle,
|
||||
url: getLegacyAppURL(context),
|
||||
text: localization.legacyMobileApp,
|
||||
),
|
||||
TextSpan(
|
||||
style: aboutTextStyle,
|
||||
text: '.',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(localization.ok.toUpperCase()),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
DrawerTile(
|
||||
company: company,
|
||||
entityType: EntityType.vendor,
|
||||
icon: getEntityIcon(EntityType.vendor),
|
||||
title: localization.vendors,
|
||||
onTap: () => store.dispatch(ViewVendorList(context)),
|
||||
onCreateTap: () {
|
||||
navigator.pop();
|
||||
store.dispatch(
|
||||
EditVendor(vendor: VendorEntity(), context: context));
|
||||
},
|
||||
),
|
||||
// STARTER: menu - do not remove comment
|
||||
DrawerTile(
|
||||
company: company,
|
||||
icon: FontAwesomeIcons.cog,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,208 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/edit/vendor_edit_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/buttons/action_icon_button.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
|
||||
class VendorEdit extends StatefulWidget {
|
||||
const VendorEdit({
|
||||
Key key,
|
||||
@required this.viewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
final VendorEditVM viewModel;
|
||||
|
||||
@override
|
||||
_VendorEditState createState() => _VendorEditState();
|
||||
}
|
||||
|
||||
class _VendorEditState extends State<VendorEdit> {
|
||||
static final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||
|
||||
// STARTER: controllers - do not remove comment
|
||||
final _nameController = TextEditingController();
|
||||
|
||||
final _address1Controller = TextEditingController();
|
||||
|
||||
final _address2Controller = TextEditingController();
|
||||
|
||||
final _cityController = TextEditingController();
|
||||
|
||||
final _stateController = TextEditingController();
|
||||
|
||||
final _postalCodeController = TextEditingController();
|
||||
|
||||
|
||||
List<TextEditingController> _controllers = [];
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
|
||||
_controllers = [
|
||||
// STARTER: array - do not remove comment
|
||||
_nameController,
|
||||
|
||||
_address1Controller,
|
||||
|
||||
_address2Controller,
|
||||
|
||||
_cityController,
|
||||
|
||||
_stateController,
|
||||
|
||||
_postalCodeController,
|
||||
|
||||
];
|
||||
|
||||
_controllers.forEach((controller) => controller.removeListener(_onChanged));
|
||||
|
||||
final vendor = widget.viewModel.vendor;
|
||||
// STARTER: read value - do not remove comment
|
||||
_nameController.text = vendor.name;
|
||||
|
||||
_address1Controller.text = vendor.address1;
|
||||
|
||||
_address2Controller.text = vendor.address2;
|
||||
|
||||
_cityController.text = vendor.city;
|
||||
|
||||
_stateController.text = vendor.state;
|
||||
|
||||
_postalCodeController.text = vendor.postalCode;
|
||||
|
||||
|
||||
_controllers.forEach((controller) => controller.addListener(_onChanged));
|
||||
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controllers.forEach((controller) {
|
||||
controller.removeListener(_onChanged);
|
||||
controller.dispose();
|
||||
});
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onChanged() {
|
||||
final vendor = widget.viewModel.vendor.rebuild((b) => b
|
||||
// STARTER: set value - do not remove comment
|
||||
..name = _nameController.text.trim()
|
||||
|
||||
..address1 = _address1Controller.text.trim()
|
||||
|
||||
..address2 = _address2Controller.text.trim()
|
||||
|
||||
..city = _cityController.text.trim()
|
||||
|
||||
..state = _stateController.text.trim()
|
||||
|
||||
..postalCode = _postalCodeController.text.trim()
|
||||
|
||||
);
|
||||
if (vendor != widget.viewModel.vendor) {
|
||||
widget.viewModel.onChanged(vendor);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final viewModel = widget.viewModel;
|
||||
final localization = AppLocalization.of(context);
|
||||
final vendor = viewModel.vendor;
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
viewModel.onBackPressed();
|
||||
return true;
|
||||
},
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(viewModel.vendor.isNew
|
||||
? localization.newVendor
|
||||
: localization.editVendor),
|
||||
actions: <Widget>[
|
||||
ActionIconButton(
|
||||
icon: Icons.cloud_upload,
|
||||
tooltip: localization.save,
|
||||
isVisible: !vendor.isDeleted,
|
||||
isDirty: vendor.isNew || vendor != viewModel.origVendor,
|
||||
isSaving: viewModel.isSaving,
|
||||
onPressed: () {
|
||||
if (! _formKey.currentState.validate()) {
|
||||
return;
|
||||
}
|
||||
viewModel.onSavePressed(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: Builder(builder: (BuildContext context) {
|
||||
return ListView(
|
||||
children: <Widget>[
|
||||
FormCard(
|
||||
children: <Widget>[
|
||||
// STARTER: widgets - do not remove comment
|
||||
TextFormField(
|
||||
controller: _nameController,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Name',
|
||||
),
|
||||
),
|
||||
|
||||
TextFormField(
|
||||
controller: _address1Controller,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Address1',
|
||||
),
|
||||
),
|
||||
|
||||
TextFormField(
|
||||
controller: _address2Controller,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Address2',
|
||||
),
|
||||
),
|
||||
|
||||
TextFormField(
|
||||
controller: _cityController,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'City',
|
||||
),
|
||||
),
|
||||
|
||||
TextFormField(
|
||||
controller: _stateController,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'State',
|
||||
),
|
||||
),
|
||||
|
||||
TextFormField(
|
||||
controller: _postalCodeController,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'PostalCode',
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
})
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/vendor_screen.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/dialogs/error_dialog.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/view/vendor_view_vm.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/vendor_model.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/edit/vendor_edit.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
|
||||
class VendorEditScreen extends StatelessWidget {
|
||||
const VendorEditScreen({Key key}) : super(key: key);
|
||||
static const String route = '/vendor/edit';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreConnector<AppState, VendorEditVM>(
|
||||
converter: (Store<AppState> store) {
|
||||
return VendorEditVM.fromStore(store);
|
||||
},
|
||||
builder: (context, viewModel) {
|
||||
return VendorEdit(
|
||||
viewModel: viewModel,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VendorEditVM {
|
||||
VendorEditVM({
|
||||
@required this.state,
|
||||
@required this.vendor,
|
||||
@required this.company,
|
||||
@required this.onChanged,
|
||||
@required this.isSaving,
|
||||
@required this.origVendor,
|
||||
@required this.onSavePressed,
|
||||
@required this.onBackPressed,
|
||||
@required this.isLoading,
|
||||
});
|
||||
|
||||
factory VendorEditVM.fromStore(Store<AppState> store) {
|
||||
final vendor = store.state.vendorUIState.editing;
|
||||
final state = store.state;
|
||||
|
||||
return VendorEditVM(
|
||||
state: state,
|
||||
isLoading: state.isLoading,
|
||||
isSaving: state.isSaving,
|
||||
origVendor: state.vendorState.map[vendor.id],
|
||||
vendor: vendor,
|
||||
company: state.selectedCompany,
|
||||
onChanged: (VendorEntity vendor) {
|
||||
store.dispatch(UpdateVendor(vendor));
|
||||
},
|
||||
onBackPressed: () {
|
||||
if (state.uiState.currentRoute.contains(VendorScreen.route)) {
|
||||
store.dispatch(UpdateCurrentRoute(vendor.isNew ? VendorScreen.route : VendorViewScreen.route));
|
||||
}
|
||||
},
|
||||
onSavePressed: (BuildContext context) {
|
||||
final Completer<VendorEntity> completer = new Completer<VendorEntity>();
|
||||
store.dispatch(SaveVendorRequest(completer: completer, vendor: vendor));
|
||||
return completer.future.then((_) {
|
||||
return completer.future.then((savedVendor) {
|
||||
store.dispatch(UpdateCurrentRoute(VendorViewScreen.route));
|
||||
if (vendor.isNew) {
|
||||
Navigator.of(context).pushReplacementNamed(VendorViewScreen.route);
|
||||
} else {
|
||||
Navigator.of(context).pop(savedVendor);
|
||||
}
|
||||
}).catchError((Object error) {
|
||||
showDialog<ErrorDialog>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ErrorDialog(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final VendorEntity vendor;
|
||||
final CompanyEntity company;
|
||||
final Function(VendorEntity) onChanged;
|
||||
final Function(BuildContext) onSavePressed;
|
||||
final Function onBackPressed;
|
||||
final bool isLoading;
|
||||
final bool isSaving;
|
||||
final VendorEntity origVendor;
|
||||
final AppState state;
|
||||
}
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/snackbar_row.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/vendor_list_item.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/vendor_list_vm.dart';
|
||||
import 'package:invoiceninja_flutter/utils/icons.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
|
||||
class VendorList extends StatelessWidget {
|
||||
const VendorList({
|
||||
Key key,
|
||||
@required this.viewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
final VendorListVM viewModel;
|
||||
|
||||
void _showMenu(
|
||||
BuildContext context, VendorEntity vendor, ClientEntity client) async {
|
||||
if (vendor == null || client == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final user = viewModel.user;
|
||||
final message = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext dialogContext) => SimpleDialog(
|
||||
children: vendor
|
||||
.getEntityActions(user: user, client: client, includeEdit: true)
|
||||
.map((entityAction) {
|
||||
if (entityAction == null) {
|
||||
return Divider();
|
||||
} else {
|
||||
return ListTile(
|
||||
leading: Icon(getEntityActionIcon(entityAction)),
|
||||
title: Text(AppLocalization.of(context)
|
||||
.lookup(entityAction.toString())),
|
||||
onTap: () {
|
||||
Navigator.of(dialogContext).pop();
|
||||
viewModel.onEntityAction(context, vendor, entityAction);
|
||||
},
|
||||
);
|
||||
}
|
||||
}).toList()));
|
||||
|
||||
if (message != null) {
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
content: SnackBarRow(
|
||||
message: message,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
/*
|
||||
final localization = AppLocalization.of(context);
|
||||
final listState = viewModel.listState;
|
||||
final filteredClientId = listState.filterEntityId;
|
||||
final filteredClient =
|
||||
filteredClientId != null ? viewModel.clientMap[filteredClientId] : null;
|
||||
*/
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
|
||||
Expanded(
|
||||
child: !viewModel.isLoaded
|
||||
? LoadingIndicator()
|
||||
: RefreshIndicator(
|
||||
onRefresh: () => viewModel.onRefreshed(context),
|
||||
child: viewModel.vendorList.isEmpty
|
||||
? Opacity(
|
||||
opacity: 0.5,
|
||||
child: Center(
|
||||
child: Text(
|
||||
AppLocalization.of(context).noRecordsFound,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: viewModel.vendorList.length,
|
||||
itemBuilder: (BuildContext context, index) {
|
||||
final vendorId = viewModel.vendorList[index];
|
||||
final vendor = viewModel.vendorMap[vendorId];
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
VendorListItem(
|
||||
user: viewModel.user,
|
||||
filter: viewModel.filter,
|
||||
vendor: vendor,
|
||||
onTap: () =>
|
||||
viewModel.onVendorTap(context, vendor),
|
||||
onEntityAction: (EntityAction action) {
|
||||
if (action == EntityAction.more) {
|
||||
_showMenu(context, vendor, null);
|
||||
} else {
|
||||
viewModel.onEntityAction(
|
||||
context, vendor, action);
|
||||
}
|
||||
},
|
||||
onLongPress: () =>
|
||||
_showMenu(context, vendor, null),
|
||||
),
|
||||
Divider(
|
||||
height: 1.0,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
/*
|
||||
filteredClient != null
|
||||
? Material(
|
||||
color: Colors.orangeAccent,
|
||||
elevation: 6.0,
|
||||
child: InkWell(
|
||||
onTap: () => viewModel.onViewEntityFilterPressed(context),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
SizedBox(width: 18.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${localization.filteredBy} ${filteredClient.listDisplayName}',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
color: Colors.white,
|
||||
),
|
||||
onPressed: () => viewModel.onClearEntityFilterPressed(),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
Expanded(
|
||||
child: !viewModel.isLoaded
|
||||
? LoadingIndicator()
|
||||
: RefreshIndicator(
|
||||
onRefresh: () => viewModel.onRefreshed(context),
|
||||
child: viewModel.vendorList.isEmpty
|
||||
? Opacity(
|
||||
opacity: 0.5,
|
||||
child: Center(
|
||||
child: Text(
|
||||
AppLocalization.of(context).noRecordsFound,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: viewModel.vendorList.length,
|
||||
itemBuilder: (BuildContext context, index) {
|
||||
final vendorId = viewModel.vendorList[index];
|
||||
final vendor = viewModel.vendorMap[vendorId];
|
||||
final client =
|
||||
viewModel.clientMap[vendor.clientId] ??
|
||||
ClientEntity();
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
VendorListItem(
|
||||
user: viewModel.user,
|
||||
filter: viewModel.filter,
|
||||
vendor: vendor,
|
||||
client:
|
||||
viewModel.clientMap[vendor.clientId] ??
|
||||
ClientEntity(),
|
||||
onTap: () =>
|
||||
viewModel.onVendorTap(context, vendor),
|
||||
onEntityAction: (EntityAction action) {
|
||||
if (action == EntityAction.more) {
|
||||
_showMenu(context, vendor, client);
|
||||
} else {
|
||||
viewModel.onEntityAction(
|
||||
context, vendor, action);
|
||||
}
|
||||
},
|
||||
onLongPress: () =>
|
||||
_showMenu(context, vendor, client),
|
||||
),
|
||||
Divider(
|
||||
height: 1.0,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),*/
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import 'package:invoiceninja_flutter/ui/app/entity_state_label.dart';
|
||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/dismissible_entity.dart';
|
||||
|
||||
class VendorListItem extends StatelessWidget {
|
||||
|
||||
const VendorListItem({
|
||||
@required this.user,
|
||||
@required this.onEntityAction,
|
||||
@required this.onTap,
|
||||
@required this.onLongPress,
|
||||
//@required this.onCheckboxChanged,
|
||||
@required this.vendor,
|
||||
@required this.filter,
|
||||
});
|
||||
|
||||
final UserEntity user;
|
||||
final Function(EntityAction) onEntityAction;
|
||||
final GestureTapCallback onTap;
|
||||
final GestureTapCallback onLongPress;
|
||||
//final ValueChanged<bool> onCheckboxChanged;
|
||||
final VendorEntity vendor;
|
||||
final String filter;
|
||||
|
||||
static final vendorItemKey = (int id) => Key('__vendor_item_${id}__');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final filterMatch = filter != null && filter.isNotEmpty
|
||||
? vendor.matchesFilterValue(filter)
|
||||
: null;
|
||||
final subtitle = filterMatch;
|
||||
|
||||
return DismissibleEntity(
|
||||
user: user,
|
||||
entity: vendor,
|
||||
onEntityAction: onEntityAction,
|
||||
child: ListTile(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
/*
|
||||
leading: Checkbox(
|
||||
//key: NinjaKeys.vendorItemCheckbox(vendor.id),
|
||||
value: true,
|
||||
//onChanged: onCheckboxChanged,
|
||||
onChanged: (value) {
|
||||
return true;
|
||||
},
|
||||
),
|
||||
*/
|
||||
title: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
vendor.name,
|
||||
//key: NinjaKeys.clientItemClientKey(client.id),
|
||||
style: Theme.of(context).textTheme.title,
|
||||
),
|
||||
),
|
||||
Text(formatNumber(vendor.listDisplayAmount, context),
|
||||
style: Theme.of(context).textTheme.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
subtitle != null && subtitle.isNotEmpty ?
|
||||
Text(
|
||||
subtitle,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
) : Container(),
|
||||
EntityStateLabel(vendor),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import 'dart:async';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
|
||||
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_selectors.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/vendor_list.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
|
||||
class VendorListBuilder extends StatelessWidget {
|
||||
const VendorListBuilder({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreConnector<AppState, VendorListVM>(
|
||||
converter: VendorListVM.fromStore,
|
||||
builder: (context, viewModel) {
|
||||
return VendorList(
|
||||
viewModel: viewModel,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VendorListVM {
|
||||
VendorListVM({
|
||||
@required this.user,
|
||||
@required this.vendorList,
|
||||
@required this.vendorMap,
|
||||
@required this.filter,
|
||||
@required this.isLoading,
|
||||
@required this.isLoaded,
|
||||
@required this.onVendorTap,
|
||||
@required this.listState,
|
||||
@required this.onRefreshed,
|
||||
@required this.onEntityAction,
|
||||
@required this.onClearEntityFilterPressed,
|
||||
@required this.onViewEntityFilterPressed,
|
||||
});
|
||||
|
||||
static VendorListVM fromStore(Store<AppState> store) {
|
||||
Future<Null> _handleRefresh(BuildContext context) {
|
||||
if (store.state.isLoading) {
|
||||
return Future<Null>(null);
|
||||
}
|
||||
final completer = snackBarCompleter(
|
||||
context, AppLocalization.of(context).refreshComplete);
|
||||
store.dispatch(LoadVendors(completer: completer, force: true));
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
final state = store.state;
|
||||
|
||||
return VendorListVM(
|
||||
user: state.user,
|
||||
listState: state.vendorListState,
|
||||
vendorList: memoizedFilteredVendorList(state.vendorState.map,
|
||||
state.vendorState.list, state.vendorListState),
|
||||
vendorMap: state.vendorState.map,
|
||||
isLoading: state.isLoading,
|
||||
isLoaded: state.vendorState.isLoaded,
|
||||
filter: state.vendorUIState.listUIState.filter,
|
||||
onClearEntityFilterPressed: () =>
|
||||
store.dispatch(FilterVendorsByEntity()),
|
||||
onViewEntityFilterPressed: (BuildContext context) => store.dispatch(
|
||||
ViewClient(
|
||||
clientId: state.vendorListState.filterEntityId,
|
||||
context: context)),
|
||||
onVendorTap: (context, vendor) {
|
||||
store.dispatch(ViewVendor(vendorId: vendor.id, context: context));
|
||||
},
|
||||
onEntityAction: (context, vendor, action) {
|
||||
switch (action) {
|
||||
case EntityAction.edit:
|
||||
store.dispatch(
|
||||
EditVendor(context: context, vendor: vendor));
|
||||
break;
|
||||
case EntityAction.clone:
|
||||
Navigator.of(context).pop();
|
||||
store.dispatch(
|
||||
EditVendor(context: context, vendor: vendor.clone));
|
||||
break;
|
||||
case EntityAction.restore:
|
||||
store.dispatch(RestoreVendorRequest(
|
||||
snackBarCompleter(
|
||||
context, AppLocalization.of(context).restoredVendor),
|
||||
vendor.id));
|
||||
break;
|
||||
case EntityAction.archive:
|
||||
store.dispatch(ArchiveVendorRequest(
|
||||
snackBarCompleter(
|
||||
context, AppLocalization.of(context).archivedVendor),
|
||||
vendor.id));
|
||||
break;
|
||||
case EntityAction.delete:
|
||||
store.dispatch(DeleteVendorRequest(
|
||||
snackBarCompleter(
|
||||
context, AppLocalization.of(context).deletedVendor),
|
||||
vendor.id));
|
||||
break;
|
||||
}
|
||||
},
|
||||
onRefreshed: (context) => _handleRefresh(context),
|
||||
);
|
||||
}
|
||||
|
||||
final UserEntity user;
|
||||
final List<int> vendorList;
|
||||
final BuiltMap<int, VendorEntity> vendorMap;
|
||||
final ListUIState listState;
|
||||
final String filter;
|
||||
final bool isLoading;
|
||||
final bool isLoaded;
|
||||
final Function(BuildContext, VendorEntity) onVendorTap;
|
||||
final Function(BuildContext) onRefreshed;
|
||||
final Function(BuildContext, VendorEntity, EntityAction) onEntityAction;
|
||||
final Function onClearEntityFilterPressed;
|
||||
final Function(BuildContext) onViewEntityFilterPressed;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:invoiceninja_flutter/redux/dashboard/dashboard_actions.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/list_filter.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/list_filter_button.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/vendor_list_vm.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/app_drawer_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/app_bottom_bar.dart';
|
||||
|
||||
class VendorScreen extends StatelessWidget {
|
||||
static const String route = '/vendor';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final store = StoreProvider.of<AppState>(context);
|
||||
final company = store.state.selectedCompany;
|
||||
final user = company.user;
|
||||
final localization = AppLocalization.of(context);
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
store.dispatch(ViewDashboard(context));
|
||||
return false;
|
||||
},
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: ListFilter(
|
||||
entityType: EntityType.vendor,
|
||||
onFilterChanged: (value) {
|
||||
store.dispatch(FilterVendors(value));
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
ListFilterButton(
|
||||
entityType: EntityType.vendor,
|
||||
onFilterPressed: (String value) {
|
||||
store.dispatch(FilterVendors(value));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
drawer: AppDrawerBuilder(),
|
||||
body: VendorListBuilder(),
|
||||
bottomNavigationBar: AppBottomBar(
|
||||
entityType: EntityType.vendor,
|
||||
onSelectedSortField: (value) => store.dispatch(SortVendors(value)),
|
||||
customValues1: company.getCustomFieldValues(CustomFieldType.vendor1,
|
||||
excludeBlank: true),
|
||||
customValues2: company.getCustomFieldValues(CustomFieldType.vendor2,
|
||||
excludeBlank: true),
|
||||
onSelectedCustom1: (value) =>
|
||||
store.dispatch(FilterVendorsByCustom1(value)),
|
||||
onSelectedCustom2: (value) =>
|
||||
store.dispatch(FilterVendorsByCustom2(value)),
|
||||
sortFields: [
|
||||
VendorFields.updatedAt,
|
||||
],
|
||||
onSelectedState: (EntityState state, value) {
|
||||
store.dispatch(FilterVendorsByState(state));
|
||||
},
|
||||
),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
|
||||
floatingActionButton: user.canCreate(EntityType.vendor)
|
||||
? FloatingActionButton(
|
||||
//key: Key(VendorKeys.vendorScreenFABKeyString),
|
||||
backgroundColor: Theme.of(context).primaryColorDark,
|
||||
onPressed: () {
|
||||
store.dispatch(
|
||||
EditVendor(vendor: VendorEntity(), context: context));
|
||||
},
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
tooltip: localization.newVendor,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/view/vendor_view_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
||||
|
||||
class VendorView extends StatefulWidget {
|
||||
|
||||
const VendorView({
|
||||
Key key,
|
||||
@required this.viewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
final VendorViewVM viewModel;
|
||||
|
||||
@override
|
||||
_VendorViewState createState() => new _VendorViewState();
|
||||
}
|
||||
|
||||
class _VendorViewState extends State<VendorView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final viewModel = widget.viewModel;
|
||||
final vendor = viewModel.vendor;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(vendor.name),
|
||||
actions: vendor.isNew
|
||||
? []
|
||||
: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.edit),
|
||||
onPressed: () {
|
||||
viewModel.onEditPressed(context);
|
||||
},
|
||||
),
|
||||
ActionMenuButton(
|
||||
user: viewModel.company.user,
|
||||
isSaving: viewModel.isSaving,
|
||||
entity: vendor,
|
||||
onSelected: viewModel.onActionSelected,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: FormCard(
|
||||
children: [
|
||||
// STARTER: widgets - do not remove comment
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
|
||||
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/vendor_screen.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/vendor_model.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||
import 'package:invoiceninja_flutter/ui/vendor/view/vendor_view.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
|
||||
class VendorViewScreen extends StatelessWidget {
|
||||
const VendorViewScreen({Key key}) : super(key: key);
|
||||
static const String route = '/vendor/view';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreConnector<AppState, VendorViewVM>(
|
||||
converter: (Store<AppState> store) {
|
||||
return VendorViewVM.fromStore(store);
|
||||
},
|
||||
builder: (context, vm) {
|
||||
return VendorView(
|
||||
viewModel: vm,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VendorViewVM {
|
||||
|
||||
VendorViewVM({
|
||||
@required this.state,
|
||||
@required this.vendor,
|
||||
@required this.company,
|
||||
@required this.onActionSelected,
|
||||
@required this.onEditPressed,
|
||||
@required this.onBackPressed,
|
||||
@required this.onRefreshed,
|
||||
@required this.isSaving,
|
||||
@required this.isLoading,
|
||||
@required this.isDirty,
|
||||
});
|
||||
|
||||
factory VendorViewVM.fromStore(Store<AppState> store) {
|
||||
final state = store.state;
|
||||
final vendor = state.vendorState.map[state.vendorUIState.selectedId];
|
||||
|
||||
Future<Null> _handleRefresh(BuildContext context) {
|
||||
final completer = snackBarCompleter(
|
||||
context, AppLocalization.of(context).refreshComplete);
|
||||
store.dispatch(LoadVendor(completer: completer, vendorId: vendor.id));
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
return VendorViewVM(
|
||||
state: state,
|
||||
company: state.selectedCompany,
|
||||
isSaving: state.isSaving,
|
||||
isLoading: state.isLoading,
|
||||
isDirty: vendor.isNew,
|
||||
vendor: vendor,
|
||||
onEditPressed: (BuildContext context) {
|
||||
store.dispatch(EditVendor(vendor: vendor, context: context));
|
||||
},
|
||||
onRefreshed: (context) => _handleRefresh(context),
|
||||
onBackPressed: () {
|
||||
if (state.uiState.currentRoute.contains(VendorScreen.route)) {
|
||||
store.dispatch(UpdateCurrentRoute(VendorScreen.route));
|
||||
}
|
||||
},
|
||||
onActionSelected: (BuildContext context, EntityAction action) {
|
||||
final localization = AppLocalization.of(context);
|
||||
switch (action) {
|
||||
case EntityAction.archive:
|
||||
store.dispatch(ArchiveVendorRequest(
|
||||
popCompleter(context, localization.archivedVendor),
|
||||
vendor.id));
|
||||
break;
|
||||
case EntityAction.delete:
|
||||
store.dispatch(DeleteVendorRequest(
|
||||
popCompleter(context, localization.deletedVendor),
|
||||
vendor.id));
|
||||
break;
|
||||
case EntityAction.restore:
|
||||
store.dispatch(RestoreVendorRequest(
|
||||
snackBarCompleter(context, localization.restoredVendor),
|
||||
vendor.id));
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final AppState state;
|
||||
final VendorEntity vendor;
|
||||
final CompanyEntity company;
|
||||
final Function(BuildContext, EntityAction) onActionSelected;
|
||||
final Function(BuildContext) onEditPressed;
|
||||
final Function onBackPressed;
|
||||
final Function(BuildContext) onRefreshed;
|
||||
final bool isSaving;
|
||||
final bool isLoading;
|
||||
final bool isDirty;
|
||||
}
|
||||
|
|
@ -88,9 +88,6 @@ class AppLocalization {
|
|||
'hosted_login': 'Hosted Login',
|
||||
'selfhost_login': 'Selfhost Login',
|
||||
'google_login': 'Google Login',
|
||||
'thanks_for_patience':
|
||||
'Thank for your patience while we work to implement these features.\n\nWe hope to have them completed in the next few months.\n\nUntil then we\'ll continue to support the',
|
||||
'legacy_mobile_app': 'legacy mobile app',
|
||||
'today': 'Today',
|
||||
'custom_range': 'Custom',
|
||||
'date_range': 'Date Range',
|
||||
|
|
@ -11465,12 +11462,6 @@ class AppLocalization {
|
|||
|
||||
String get googleLogin => _localizedValues[locale.toString()]['google_login'];
|
||||
|
||||
String get thanksForPatience =>
|
||||
_localizedValues[locale.toString()]['thanks_for_patience'];
|
||||
|
||||
String get legacyMobileApp =>
|
||||
_localizedValues[locale.toString()]['legacy_mobile_app'];
|
||||
|
||||
String get today => _localizedValues[locale.toString()]['today'];
|
||||
|
||||
String get customRange => _localizedValues[locale.toString()]['custom_range'];
|
||||
|
|
|
|||
Loading…
Reference in New Issue