Subscriptions

This commit is contained in:
Hillel Coren 2021-03-24 20:23:43 +02:00
parent f5d3486dac
commit 7ecdb6c6a5
28 changed files with 166 additions and 149 deletions

View File

@ -517,7 +517,7 @@ abstract class CompanyEntity extends Object
..passwordTimeout = 30 * 60 * 1000 ..passwordTimeout = 30 * 60 * 1000
..oauthPasswordRequired = false ..oauthPasswordRequired = false
..invoiceTaskDatelog = true ..invoiceTaskDatelog = true
..subscriptions = BuiltList<SubscriptionEntity>(); ..subscriptions.replace(BuiltList<SubscriptionEntity>());
static Serializer<CompanyEntity> get serializer => _$companyEntitySerializer; static Serializer<CompanyEntity> get serializer => _$companyEntitySerializer;
} }

View File

@ -8,6 +8,7 @@ export 'package:invoiceninja_flutter/data/models/company_model.dart';
export 'package:invoiceninja_flutter/data/models/credit_model.dart'; export 'package:invoiceninja_flutter/data/models/credit_model.dart';
export 'package:invoiceninja_flutter/data/models/tax_rate_model.dart'; export 'package:invoiceninja_flutter/data/models/tax_rate_model.dart';
export 'package:invoiceninja_flutter/data/models/document_model.dart'; export 'package:invoiceninja_flutter/data/models/document_model.dart';
export 'package:invoiceninja_flutter/data/models/settings_model.dart';
export 'package:invoiceninja_flutter/data/models/entities.dart'; export 'package:invoiceninja_flutter/data/models/entities.dart';
export 'package:invoiceninja_flutter/data/models/expense_model.dart'; export 'package:invoiceninja_flutter/data/models/expense_model.dart';
export 'package:invoiceninja_flutter/data/models/subscription_model.dart'; export 'package:invoiceninja_flutter/data/models/subscription_model.dart';

View File

@ -46,7 +46,8 @@ abstract class SubscriptionItemResponse
} }
class SubscriptionFields { class SubscriptionFields {
// STARTER: fields - do not remove comment static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
} }
abstract class SubscriptionEntity extends Object abstract class SubscriptionEntity extends Object

View File

@ -47,7 +47,6 @@ List<String> filteredClientsSelector(
ListUIState clientListState, ListUIState clientListState,
BuiltMap<String, UserEntity> userMap, BuiltMap<String, UserEntity> userMap,
StaticState staticState) { StaticState staticState) {
final filterEntityId = selectionState.filterEntityId; final filterEntityId = selectionState.filterEntityId;
final filterEntityType = selectionState.filterEntityType; final filterEntityType = selectionState.filterEntityType;

View File

@ -6,6 +6,7 @@ import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/data/models/user_model.dart'; import 'package:invoiceninja_flutter/data/models/user_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/auth/auth_actions.dart'; import 'package:invoiceninja_flutter/redux/auth/auth_actions.dart';

View File

@ -1,4 +1,5 @@
import 'package:invoiceninja_flutter/data/models/subscription_model.dart'; import 'package:invoiceninja_flutter/data/models/subscription_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/static/static_state.dart'; import 'package:invoiceninja_flutter/redux/static/static_state.dart';
import 'package:memoize/memoize.dart'; import 'package:memoize/memoize.dart';
import 'package:built_collection/built_collection.dart'; import 'package:built_collection/built_collection.dart';
@ -6,16 +7,19 @@ import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart'; import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
var memoizedDropdownSubscriptionList = memo5( var memoizedDropdownSubscriptionList = memo5(
(BuiltMap<String, SubscriptionEntity> subscriptionMap, BuiltList<String> subscriptionList, (BuiltMap<String, SubscriptionEntity> subscriptionMap,
StaticState staticState, BuiltList<String> subscriptionList,
BuiltMap<String, UserEntity> userMap, StaticState staticState,
BuiltMap<String, UserEntity> userMap,
String clientId) => String clientId) =>
dropdownSubscriptionsSelector(subscriptionMap, subscriptionList, staticState, userMap, clientId)); dropdownSubscriptionsSelector(
subscriptionMap, subscriptionList, staticState, userMap, clientId));
List<String> dropdownSubscriptionsSelector(BuiltMap<String, SubscriptionEntity> subscriptionMap, List<String> dropdownSubscriptionsSelector(
BuiltList<String> subscriptionList, BuiltMap<String, SubscriptionEntity> subscriptionMap,
BuiltList<String> subscriptionList,
StaticState staticState, StaticState staticState,
BuiltMap<String, UserEntity> userMap, BuiltMap<String, UserEntity> userMap,
String clientId) { String clientId) {
final list = subscriptionList.where((subscriptionId) { final list = subscriptionList.where((subscriptionId) {
final subscription = subscriptionMap[subscriptionId]; final subscription = subscriptionMap[subscriptionId];
@ -30,64 +34,60 @@ List<String> dropdownSubscriptionsSelector(BuiltMap<String, SubscriptionEntity>
list.sort((subscriptionAId, subscriptionBId) { list.sort((subscriptionAId, subscriptionBId) {
final subscriptionA = subscriptionMap[subscriptionAId]; final subscriptionA = subscriptionMap[subscriptionAId];
final subscriptionB = subscriptionMap[subscriptionBId]; final subscriptionB = subscriptionMap[subscriptionBId];
return subscriptionA.compareTo(subscriptionB, SubscriptionFields.name, true); return subscriptionA.compareTo(
subscriptionB, SubscriptionFields.createdAt, true);
}); });
return list; return list;
} }
var memoizedFilteredSubscriptionList = memo7(( var memoizedFilteredSubscriptionList = memo4((SelectionState selectionState,
String filterEntityId,
EntityType filterEntityType,
BuiltMap<String, SubscriptionEntity> subscriptionMap, BuiltMap<String, SubscriptionEntity> subscriptionMap,
BuiltList<String> subscriptionList, BuiltList<String> subscriptionList,
StaticState staticState,
BuiltMap<String, UserEntity> userMap,
ListUIState subscriptionListState) => ListUIState subscriptionListState) =>
filteredSubscriptionsSelector(filterEntityId, filterEntityType, subscriptionMap, subscriptionList, staticState, userMap, subscriptionListState)); filteredSubscriptionsSelector(
selectionState,
subscriptionMap,
subscriptionList,
subscriptionListState,
));
List<String> filteredSubscriptionsSelector( List<String> filteredSubscriptionsSelector(
String filterEntityId, SelectionState selectionState,
EntityType filterEntityType,
BuiltMap<String, SubscriptionEntity> subscriptionMap, BuiltMap<String, SubscriptionEntity> subscriptionMap,
BuiltList<String> subscriptionList, BuiltList<String> subscriptionList,
StaticState staticState,
BuiltMap<String, UserEntity> userMap,
ListUIState subscriptionListState) { ListUIState subscriptionListState) {
final filterEntityId = selectionState.filterEntityId;
final filterEntityType = selectionState.filterEntityType;
final list = subscriptionList.where((subscriptionId) { final list = subscriptionList.where((subscriptionId) {
final subscription = subscriptionMap[subscriptionId]; final subscription = subscriptionMap[subscriptionId];
if (subscription.id == selectionState.selectedId) {
return true;
}
if (filterEntityId != null && subscription.id != filterEntityId) { if (filterEntityId != null && subscription.id != filterEntityId) {
return false; return false;
} else { } else {}
}
if (!subscription.matchesStates(subscriptionListState.stateFilters)) { if (!subscription.matchesStates(subscriptionListState.stateFilters)) {
return false; return false;
} }
if (subscriptionListState.custom1Filters.isNotEmpty &&
!subscriptionListState.custom1Filters.contains(subscription.customValue1)) {
return false;
}
if (subscriptionListState.custom2Filters.isNotEmpty &&
!subscriptionListState.custom2Filters.contains(subscription.customValue2)) {
return false;
}
return subscription.matchesFilter(subscriptionListState.filter); return subscription.matchesFilter(subscriptionListState.filter);
}).toList(); }).toList();
list.sort((subscriptionAId, subscriptionBId) { list.sort((subscriptionAId, subscriptionBId) {
return subscriptionMap[subscriptionAId].compareTo( final subscriptionA = subscriptionMap[subscriptionAId];
subscription: subscriptionMap[subscriptionBId], final subscriptionB = subscriptionMap[subscriptionBId];
sortField: subscriptionListState.sortField, return subscriptionA.compareTo(subscriptionB,
sortAscending: subscriptionListState.sortAscending, subscriptionListState.sortField, subscriptionListState.sortAscending);
);
}); });
return list; return list;
} }
bool hasSubscriptionChanges( bool hasSubscriptionChanges(SubscriptionEntity subscription,
SubscriptionEntity subscription, BuiltMap<String, SubscriptionEntity> subscriptionMap) => BuiltMap<String, SubscriptionEntity> subscriptionMap) =>
subscription.isNew ? subscription.isChanged : subscription != subscriptionMap[subscription.id]; subscription.isNew
? subscription.isChanged
: subscription != subscriptionMap[subscription.id];

View File

@ -9,8 +9,8 @@ import 'package:invoiceninja_flutter/data/models/models.dart';
part 'subscription_state.g.dart'; part 'subscription_state.g.dart';
abstract class SubscriptionState implements Built<SubscriptionState, SubscriptionStateBuilder> { abstract class SubscriptionState
implements Built<SubscriptionState, SubscriptionStateBuilder> {
factory SubscriptionState() { factory SubscriptionState() {
return _$SubscriptionState._( return _$SubscriptionState._(
map: BuiltMap<String, SubscriptionEntity>(), map: BuiltMap<String, SubscriptionEntity>(),
@ -46,15 +46,16 @@ abstract class SubscriptionState implements Built<SubscriptionState, Subscriptio
..list.replace((map.keys.toList() + list.toList()).toSet().toList())); ..list.replace((map.keys.toList() + list.toList()).toSet().toList()));
} }
static Serializer<SubscriptionState> get serializer =>
static Serializer<SubscriptionState> get serializer => _$subscriptionStateSerializer; _$subscriptionStateSerializer;
} }
abstract class SubscriptionUIState extends Object with EntityUIState implements Built<SubscriptionUIState, SubscriptionUIStateBuilder> { abstract class SubscriptionUIState extends Object
with EntityUIState
implements Built<SubscriptionUIState, SubscriptionUIStateBuilder> {
factory SubscriptionUIState() { factory SubscriptionUIState() {
return _$SubscriptionUIState._( return _$SubscriptionUIState._(
listUIState: ListUIState(SubscriptionFields.name), listUIState: ListUIState(SubscriptionFields.createdAt),
editing: SubscriptionEntity(), editing: SubscriptionEntity(),
selectedId: '', selectedId: '',
tabIndex: 0, tabIndex: 0,
@ -63,7 +64,7 @@ abstract class SubscriptionUIState extends Object with EntityUIState implements
SubscriptionUIState._(); SubscriptionUIState._();
@override @override
@memoized @memoized
int get hashCode; int get hashCode;
@nullable @nullable
@ -75,5 +76,6 @@ abstract class SubscriptionUIState extends Object with EntityUIState implements
@override @override
String get editingId => editing.id; String get editingId => editing.id;
static Serializer<SubscriptionUIState> get serializer => _$subscriptionUIStateSerializer; static Serializer<SubscriptionUIState> get serializer =>
} _$subscriptionUIStateSerializer;
}

View File

@ -5,6 +5,7 @@ import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/invoice_model.dart'; import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_selectors.dart'; import 'package:invoiceninja_flutter/redux/invoice/invoice_selectors.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart'; import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart'; import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart';

View File

@ -6,6 +6,7 @@ import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart'; import 'package:invoiceninja_flutter/redux/group/group_actions.dart';

View File

@ -11,6 +11,7 @@ import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/document_model.dart'; import 'package:invoiceninja_flutter/data/models/document_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';

View File

@ -6,6 +6,7 @@ import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart'; import 'package:invoiceninja_flutter/redux/group/group_actions.dart';

View File

@ -6,6 +6,7 @@ import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart'; import 'package:invoiceninja_flutter/redux/group/group_actions.dart';

View File

@ -8,6 +8,7 @@ import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';

View File

@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart'; import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart'; import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart'; import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart';

View File

@ -6,6 +6,7 @@ import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart'; import 'package:invoiceninja_flutter/redux/group/group_actions.dart';

View File

@ -6,6 +6,7 @@ import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart'; import 'package:invoiceninja_flutter/redux/group/group_actions.dart';

View File

@ -3,6 +3,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart'; import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
import 'package:invoiceninja_flutter/ui/settings/tax_settings.dart'; import 'package:invoiceninja_flutter/ui/settings/tax_settings.dart';

View File

@ -6,6 +6,7 @@ import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart'; import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/group_model.dart'; import 'package:invoiceninja_flutter/data/models/group_model.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart'; import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
import 'package:invoiceninja_flutter/redux/group/group_actions.dart'; import 'package:invoiceninja_flutter/redux/group/group_actions.dart';

View File

@ -1,7 +1,6 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/settings_model.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart'; import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart'; import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart';

View File

@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/edit_scaffold.dart'; import 'package:invoiceninja_flutter/ui/app/edit_scaffold.dart';
import 'package:invoiceninja_flutter/ui/app/form_card.dart'; import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/subscription/edit/subscription_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/subscription/edit/subscription_edit_vm.dart';
import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart'; import 'package:invoiceninja_flutter/utils/completers.dart';
@ -19,30 +20,27 @@ class SubscriptionEdit extends StatefulWidget {
} }
class _SubscriptionEditState extends State<SubscriptionEdit> { class _SubscriptionEditState extends State<SubscriptionEdit> {
static final GlobalKey<FormState> _formKey = GlobalKey<FormState>(debugLabel: '_subscriptionEdit'); static final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(debugLabel: '_subscriptionEdit');
final _debouncer = Debouncer(); final _debouncer = Debouncer();
// STARTER: controllers - do not remove comment // STARTER: controllers - do not remove comment
final _subscriptionsController = TextEditingController(); final _subscriptionsController = TextEditingController();
List<TextEditingController> _controllers = []; List<TextEditingController> _controllers = [];
@override @override
void didChangeDependencies() { void didChangeDependencies() {
_controllers = [ _controllers = [
// STARTER: array - do not remove comment // STARTER: array - do not remove comment
_subscriptionsController, _subscriptionsController,
]; ];
_controllers.forEach((controller) => controller.removeListener(_onChanged)); _controllers.forEach((controller) => controller.removeListener(_onChanged));
final subscription = widget.viewModel.subscription; final subscription = widget.viewModel.subscription;
// STARTER: read value - do not remove comment // STARTER: read value - do not remove comment
_subscriptionsController.text = subscription.subscriptions; //_subscriptionsController.text = subscription.subscriptions;
_controllers.forEach((controller) => controller.addListener(_onChanged)); _controllers.forEach((controller) => controller.addListener(_onChanged));
@ -61,15 +59,13 @@ _subscriptionsController.text = subscription.subscriptions;
void _onChanged() { void _onChanged() {
_debouncer.run(() { _debouncer.run(() {
final subscription = widget.viewModel.subscription.rebuild((b) => b
final subscription = widget.viewModel.subscription.rebuild((b) => b // STARTER: set value - do not remove comment
// STARTER: set value - do not remove comment //..subscriptions = _subscriptionsController.text.trim()
..subscriptions = _subscriptionsController.text.trim() );
if (subscription != widget.viewModel.subscription) {
);
if (subscription != widget.viewModel.subscription) {
widget.viewModel.onChanged(subscription); widget.viewModel.onChanged(subscription);
} }
}); });
} }
@ -80,46 +76,45 @@ _subscriptionsController.text = subscription.subscriptions;
final subscription = viewModel.subscription; final subscription = viewModel.subscription;
return EditScaffold( return EditScaffold(
title: subscription.isNew ? localization.newSubscription : localization.editSubscription, title: subscription.isNew
? localization.newSubscription
: localization.editSubscription,
onCancelPressed: (context) => viewModel.onCancelPressed(context), onCancelPressed: (context) => viewModel.onCancelPressed(context),
onSavePressed: (context) { onSavePressed: (context) {
final bool isValid = _formKey.currentState.validate(); final bool isValid = _formKey.currentState.validate();
/* /*
setState(() { setState(() {
_autoValidate = !isValid; _autoValidate = !isValid;
}); });
*/ */
if (!isValid) { if (!isValid) {
return; return;
} }
viewModel.onSavePressed(context); viewModel.onSavePressed(context);
}, },
body:Form( body: Form(
key: _formKey, key: _formKey,
child: Builder(builder: (BuildContext context) { child: Builder(builder: (BuildContext context) {
return ScrollableListView( return ScrollableListView(
children: <Widget>[ children: <Widget>[
FormCard( FormCard(
children: <Widget>[ children: <Widget>[
// STARTER: widgets - do not remove comment // STARTER: widgets - do not remove comment
TextFormField( TextFormField(
controller: _subscriptionsController, controller: _subscriptionsController,
autocorrect: false, autocorrect: false,
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Subscriptions', labelText: 'Subscriptions',
), ),
), ),
],
], ),
), ],
], );
); })),
})
),
); );
} }
} }

View File

@ -47,7 +47,9 @@ class SubscriptionListItem extends StatelessWidget {
userCompany: state.userCompany, userCompany: state.userCompany,
entity: subscription, entity: subscription,
isSelected: subscription.id == isSelected: subscription.id ==
(uiState.isEditing ? subscriptionUIState.editing.id : subscriptionUIState.selectedId), (uiState.isEditing
? subscriptionUIState.editing.id
: subscriptionUIState.selectedId),
child: ListTile( child: ListTile(
onTap: () => onTap != null onTap: () => onTap != null
? onTap() ? onTap()
@ -73,7 +75,7 @@ class SubscriptionListItem extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: Text( child: Text(
subscription.name, subscription.id,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.headline6,
), ),
), ),

View File

@ -47,7 +47,8 @@ class SubscriptionListBuilder extends StatelessWidget {
user: viewModel.state.user, user: viewModel.state.user,
filter: viewModel.filter, filter: viewModel.filter,
subscription: subscription, subscription: subscription,
isChecked: isInMultiselect && listState.isSelected(subscription.id), isChecked:
isInMultiselect && listState.isSelected(subscription.id),
); );
}); });
}, },
@ -85,23 +86,27 @@ class SubscriptionListVM {
final state = store.state; final state = store.state;
return SubscriptionListVM( return SubscriptionListVM(
state: state, state: state,
userCompany: state.userCompany, userCompany: state.userCompany,
listState: state.subscriptionListState, listState: state.subscriptionListState,
subscriptionList: memoizedFilteredSubscriptionList(state.subscriptionState.map, subscriptionList: memoizedFilteredSubscriptionList(
state.subscriptionState.list, state.subscriptionListState), state.getUISelection(EntityType.subscription),
subscriptionMap: state.subscriptionState.map, state.subscriptionState.map,
isLoading: state.isLoading, state.subscriptionState.list,
filter: state.subscriptionUIState.listUIState.filter, state.subscriptionListState,
onEntityAction: ),
(BuildContext context, List<BaseEntity> subscriptions, EntityAction action) => subscriptionMap: state.subscriptionState.map,
isLoading: state.isLoading,
filter: state.subscriptionUIState.listUIState.filter,
onEntityAction: (BuildContext context, List<BaseEntity> subscriptions,
EntityAction action) =>
handleSubscriptionAction(context, subscriptions, action), handleSubscriptionAction(context, subscriptions, action),
onRefreshed: (context) => _handleRefresh(context), onRefreshed: (context) => _handleRefresh(context),
tableColumns: tableColumns:
state.userCompany.settings.getTableColumns(EntityType.subscription) ?? state.userCompany.settings.getTableColumns(EntityType.subscription) ??
SubscriptionPresenter.getDefaultTableFields(state.userCompany), SubscriptionPresenter.getDefaultTableFields(state.userCompany),
onSortColumn: (field) => store.dispatch(SortSubscriptions(field)), onSortColumn: (field) => store.dispatch(SortSubscriptions(field)),
onClearMultielsect: () => store.dispatch(ClearSubscriptionMultiselect()), onClearMultielsect: () => store.dispatch(ClearSubscriptionMultiselect()),
); );
} }
@ -117,4 +122,4 @@ class SubscriptionListVM {
final List<String> tableColumns; final List<String> tableColumns;
final Function(String) onSortColumn; final Function(String) onSortColumn;
final Function onClearMultielsect; final Function onClearMultielsect;
} }

View File

@ -34,7 +34,8 @@ class SubscriptionScreen extends StatelessWidget {
return ListScaffold( return ListScaffold(
entityType: EntityType.subscription, entityType: EntityType.subscription,
onHamburgerLongPress: () => store.dispatch(StartSubscriptionMultiselect()), onHamburgerLongPress: () =>
store.dispatch(StartSubscriptionMultiselect()),
appBarTitle: ListFilter( appBarTitle: ListFilter(
entityIds: viewModel.subscriptionList, entityIds: viewModel.subscriptionList,
filter: state.subscriptionListState.filter, filter: state.subscriptionListState.filter,
@ -46,13 +47,13 @@ class SubscriptionScreen extends StatelessWidget {
bottomNavigationBar: AppBottomBar( bottomNavigationBar: AppBottomBar(
entityType: EntityType.subscription, entityType: EntityType.subscription,
tableColumns: SubscriptionPresenter.getAllTableFields(userCompany), tableColumns: SubscriptionPresenter.getAllTableFields(userCompany),
defaultTableColumns: SubscriptionPresenter.getDefaultTableFields(userCompany), defaultTableColumns:
SubscriptionPresenter.getDefaultTableFields(userCompany),
onSelectedSortField: (value) { onSelectedSortField: (value) {
store.dispatch(SortSubscriptions(value)); store.dispatch(SortSubscriptions(value));
}, },
sortFields: [ sortFields: [
SubscriptionFields.name, SubscriptionFields.createdAt,
SubscriptionFields.balance,
SubscriptionFields.updatedAt, SubscriptionFields.updatedAt,
], ],
onSelectedState: (EntityState state, value) { onSelectedState: (EntityState state, value) {
@ -65,14 +66,6 @@ class SubscriptionScreen extends StatelessWidget {
store.dispatch(StartSubscriptionMultiselect()); store.dispatch(StartSubscriptionMultiselect());
} }
}, },
customValues1: company.getCustomFieldValues(CustomFieldType.subscription1,
excludeBlank: true),
customValues2: company.getCustomFieldValues(CustomFieldType.subscription2,
excludeBlank: true),
customValues3: company.getCustomFieldValues(CustomFieldType.subscription3,
excludeBlank: true),
customValues4: company.getCustomFieldValues(CustomFieldType.subscription4,
excludeBlank: true),
onSelectedCustom1: (value) => onSelectedCustom1: (value) =>
store.dispatch(FilterSubscriptionsByCustom1(value)), store.dispatch(FilterSubscriptionsByCustom1(value)),
onSelectedCustom2: (value) => onSelectedCustom2: (value) =>
@ -82,7 +75,8 @@ class SubscriptionScreen extends StatelessWidget {
onSelectedCustom4: (value) => onSelectedCustom4: (value) =>
store.dispatch(FilterSubscriptionsByCustom4(value)), store.dispatch(FilterSubscriptionsByCustom4(value)),
), ),
floatingActionButton: state.prefState.isMenuFloated && userCompany.canCreate(EntityType.subscription) floatingActionButton: state.prefState.isMenuFloated &&
userCompany.canCreate(EntityType.subscription)
? FloatingActionButton( ? FloatingActionButton(
heroTag: 'subscription_fab', heroTag: 'subscription_fab',
backgroundColor: Theme.of(context).primaryColorDark, backgroundColor: Theme.of(context).primaryColorDark,

View File

@ -47,8 +47,12 @@ class SubscriptionScreenVM {
return SubscriptionScreenVM( return SubscriptionScreenVM(
subscriptionMap: state.subscriptionState.map, subscriptionMap: state.subscriptionState.map,
subscriptionList: memoizedFilteredSubscriptionList(state.subscriptionState.map, subscriptionList: memoizedFilteredSubscriptionList(
state.subscriptionState.list, state.subscriptionListState), state.getUISelection(EntityType.subscription),
state.subscriptionState.map,
state.subscriptionState.list,
state.subscriptionListState,
),
userCompany: state.userCompany, userCompany: state.userCompany,
isInMultiselect: state.subscriptionListState.isInMultiselect(), isInMultiselect: state.subscriptionListState.isInMultiselect(),
onEntityAction: (BuildContext context, List<BaseEntity> subscriptions, onEntityAction: (BuildContext context, List<BaseEntity> subscriptions,

View File

@ -1,10 +1,10 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/subscription/view/subscription_view_vm.dart'; import 'package:invoiceninja_flutter/ui/subscription/view/subscription_view_vm.dart';
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart'; import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
class SubscriptionView extends StatefulWidget { class SubscriptionView extends StatefulWidget {
const SubscriptionView({ const SubscriptionView({
Key key, Key key,
@required this.viewModel, @required this.viewModel,
@ -28,8 +28,7 @@ class _SubscriptionViewState extends State<SubscriptionView> {
isFilter: widget.isFilter, isFilter: widget.isFilter,
entity: subscription, entity: subscription,
body: ScrollableListView( body: ScrollableListView(
children: <Widget>[ children: <Widget>[],
],
), ),
); );
} }

View File

@ -1,5 +1,6 @@
import 'package:invoiceninja_flutter/data/models/stub_model.dart'; import 'package:invoiceninja_flutter/data/models/stub_model.dart';
import 'package:invoiceninja_flutter/redux/static/static_state.dart'; import 'package:invoiceninja_flutter/redux/static/static_state.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:memoize/memoize.dart'; import 'package:memoize/memoize.dart';
import 'package:built_collection/built_collection.dart'; import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/data/models/models.dart';
@ -36,9 +37,8 @@ List<String> dropdownStubsSelector(BuiltMap<String, StubEntity> stubMap,
return list; return list;
} }
var memoizedFilteredStubList = memo7(( var memoizedFilteredStubList = memo6((
String filterEntityId, SelectionState selectionState,
EntityType filterEntityType,
BuiltMap<String, StubEntity> stubMap, BuiltMap<String, StubEntity> stubMap,
BuiltList<String> stubList, BuiltList<String> stubList,
StaticState staticState, StaticState staticState,
@ -47,13 +47,16 @@ var memoizedFilteredStubList = memo7((
filteredStubsSelector(filterEntityId, filterEntityType, stubMap, stubList, staticState, userMap, stubListState)); filteredStubsSelector(filterEntityId, filterEntityType, stubMap, stubList, staticState, userMap, stubListState));
List<String> filteredStubsSelector( List<String> filteredStubsSelector(
String filterEntityId, SelectionState selectionState,
EntityType filterEntityType,
BuiltMap<String, StubEntity> stubMap, BuiltMap<String, StubEntity> stubMap,
BuiltList<String> stubList, BuiltList<String> stubList,
StaticState staticState, StaticState staticState,
BuiltMap<String, UserEntity> userMap, BuiltMap<String, UserEntity> userMap,
ListUIState stubListState) { ListUIState stubListState) {
final filterEntityId = selectionState.filterEntityId;
final filterEntityType = selectionState.filterEntityType;
final list = stubList.where((stubId) { final list = stubList.where((stubId) {
final stub = stubMap[stubId]; final stub = stubMap[stubId];
if (filterEntityId != null && stub.id != filterEntityId) { if (filterEntityId != null && stub.id != filterEntityId) {
@ -77,11 +80,10 @@ List<String> filteredStubsSelector(
}).toList(); }).toList();
list.sort((stubAId, stubBId) { list.sort((stubAId, stubBId) {
return stubMap[stubAId].compareTo( final stubA = stubMap[stubAId];
stub: stubMap[stubBId], final stubB = stubMap[stubBId];
sortField: stubListState.sortField, return clientA.compareTo(stubB, stubListState.sortField,
sortAscending: stubListState.sortAscending, stubListState.sortAscending, userMap, staticState);
);
}); });

View File

@ -5,6 +5,7 @@ import 'package:invoiceninja_flutter/ui/app/form_card.dart';
import 'package:invoiceninja_flutter/ui/stub/edit/stub_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/stub/edit/stub_edit_vm.dart';
import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/completers.dart'; import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
class StubEdit extends StatefulWidget { class StubEdit extends StatefulWidget {
const StubEdit({ const StubEdit({

View File

@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/stub/view/stub_view_vm.dart'; import 'package:invoiceninja_flutter/ui/stub/view/stub_view_vm.dart';
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart'; import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';