Added redux logic for Table/List

This commit is contained in:
Gianfranco Gasbarri 2019-11-17 13:03:10 +00:00
parent 5f3501c3de
commit 2359b1b2f6
11 changed files with 136 additions and 28 deletions

View File

@ -91,6 +91,7 @@ Serializers _$serializers = (new Serializers().toBuilder()
..add(LanguageListResponse.serializer) ..add(LanguageListResponse.serializer)
..add(ListUIState.serializer) ..add(ListUIState.serializer)
..add(LoginResponse.serializer) ..add(LoginResponse.serializer)
..add(ModuleLayout.serializer)
..add(PaymentEntity.serializer) ..add(PaymentEntity.serializer)
..add(PaymentItemResponse.serializer) ..add(PaymentItemResponse.serializer)
..add(PaymentListResponse.serializer) ..add(PaymentListResponse.serializer)

View File

@ -59,7 +59,7 @@ import 'package:invoiceninja_flutter/ui/company_gateway/view/company_gateway_vie
import 'package:invoiceninja_flutter/redux/company_gateway/company_gateway_middleware.dart'; import 'package:invoiceninja_flutter/redux/company_gateway/company_gateway_middleware.dart';
void main({bool isTesting = false}) async { void main({bool isTesting = false}) async {
//WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
final SentryClient _sentry = Config.SENTRY_DNS.isEmpty final SentryClient _sentry = Config.SENTRY_DNS.isEmpty
? null ? null

View File

@ -36,6 +36,8 @@ class RefreshClient {
final String clientId; final String clientId;
} }
class SwitchListTableLayout implements PersistUI, PersistPrefs {}
class ViewMainScreen { class ViewMainScreen {
ViewMainScreen(this.context); ViewMainScreen(this.context);

View File

@ -217,7 +217,7 @@ Middleware<AppState> _createLoadState(
uiState.currentRoute.isNotEmpty) { uiState.currentRoute.isNotEmpty) {
final NavigatorState navigator = Navigator.of(action.context); final NavigatorState navigator = Navigator.of(action.context);
final routes = _getRoutes(appState); final routes = _getRoutes(appState);
if (appState.prefState.layout == AppLayout.mobile) { if (appState.prefState.appLayout == AppLayout.mobile) {
bool isFirst = true; bool isFirst = true;
routes.forEach((route) { routes.forEach((route) {
if (isFirst) { if (isFirst) {
@ -250,7 +250,7 @@ Middleware<AppState> _createLoadState(
final Completer<Null> completer = Completer<Null>(); final Completer<Null> completer = Completer<Null>();
completer.future.then((_) { completer.future.then((_) {
final layout = calculateLayout(action.context); final layout = calculateLayout(action.context);
if (store.state.prefState.layout == AppLayout.tablet && if (store.state.prefState.appLayout == AppLayout.tablet &&
layout == AppLayout.mobile) { layout == AppLayout.mobile) {
store.dispatch(UserSettingsChanged(layout: layout)); store.dispatch(UserSettingsChanged(layout: layout));
store.dispatch( store.dispatch(

View File

@ -27,7 +27,8 @@ PrefState prefReducer(
return state.rebuild((b) => b return state.rebuild((b) => b
..companyPrefs[selectedCompanyIndex] = ..companyPrefs[selectedCompanyIndex] =
companyPrefReducer(state.companyPrefs[selectedCompanyIndex], action) companyPrefReducer(state.companyPrefs[selectedCompanyIndex], action)
..layout = layoutReducer(state.layout, action) ..appLayout = layoutReducer(state.appLayout, action)
..moduleLayout = moduleLayoutReducer(state.moduleLayout, action)
..menuSidebarMode = manuSidebarReducer(state.menuSidebarMode, action) ..menuSidebarMode = manuSidebarReducer(state.menuSidebarMode, action)
..historySidebarMode = ..historySidebarMode =
historySidebarReducer(state.historySidebarMode, action) historySidebarReducer(state.historySidebarMode, action)
@ -92,6 +93,16 @@ Reducer<AppLayout> layoutReducer = combineReducers([
}), }),
]); ]);
Reducer<ModuleLayout> moduleLayoutReducer = combineReducers([
TypedReducer<ModuleLayout, SwitchListTableLayout>((moduleLayout, action) {
if (moduleLayout == ModuleLayout.list) {
return ModuleLayout.table;
} else {
return ModuleLayout.list;
}
}),
]);
Reducer<AppSidebarMode> manuSidebarReducer = combineReducers([ Reducer<AppSidebarMode> manuSidebarReducer = combineReducers([
TypedReducer<AppSidebarMode, UserSettingsChanged>((mode, action) { TypedReducer<AppSidebarMode, UserSettingsChanged>((mode, action) {
return action.menuMode ?? mode; return action.menuMode ?? mode;

View File

@ -10,7 +10,8 @@ part 'pref_state.g.dart';
abstract class PrefState implements Built<PrefState, PrefStateBuilder> { abstract class PrefState implements Built<PrefState, PrefStateBuilder> {
factory PrefState() { factory PrefState() {
return _$PrefState._( return _$PrefState._(
layout: AppLayout.tablet, appLayout: AppLayout.tablet,
moduleLayout: ModuleLayout.list,
menuSidebarMode: AppSidebarMode.collapse, menuSidebarMode: AppSidebarMode.collapse,
historySidebarMode: AppSidebarMode.visible, historySidebarMode: AppSidebarMode.visible,
isMenuVisible: false, isMenuVisible: false,
@ -30,7 +31,9 @@ abstract class PrefState implements Built<PrefState, PrefStateBuilder> {
PrefState._(); PrefState._();
AppLayout get layout; AppLayout get appLayout;
ModuleLayout get moduleLayout;
AppSidebarMode get menuSidebarMode; AppSidebarMode get menuSidebarMode;
@ -59,10 +62,10 @@ abstract class PrefState implements Built<PrefState, PrefStateBuilder> {
bool get isMobile => layout == AppLayout.mobile; bool get isMobile => layout == AppLayout.mobile;
bool get isMenuFloated => bool get isMenuFloated =>
layout == AppLayout.mobile || menuSidebarMode == AppSidebarMode.float; appLayout == AppLayout.mobile || menuSidebarMode == AppSidebarMode.float;
bool get isHistoryFloated => bool get isHistoryFloated =>
layout == AppLayout.mobile || historySidebarMode == AppSidebarMode.float; appLayout == AppLayout.mobile || historySidebarMode == AppSidebarMode.float;
bool get showMenu => bool get showMenu =>
(isMenuVisible && menuSidebarMode == AppSidebarMode.visible) || (isMenuVisible && menuSidebarMode == AppSidebarMode.visible) ||
@ -112,6 +115,19 @@ class AppLayout extends EnumClass {
static AppLayout valueOf(String name) => _$valueOf(name); static AppLayout valueOf(String name) => _$valueOf(name);
} }
class ModuleLayout extends EnumClass {
const ModuleLayout._(String name) : super(name);
static Serializer<ModuleLayout> get serializer => _$moduleLayoutSerializer;
static const ModuleLayout list = _$list;
static const ModuleLayout table = _$table;
static BuiltSet<ModuleLayout> get values => _$moduleLayoutValues;
static ModuleLayout valueOf(String name) => _$moduleLayoutValueOf(name);
}
class AppSidebar extends EnumClass { class AppSidebar extends EnumClass {
const AppSidebar._(String name) : super(name); const AppSidebar._(String name) : super(name);

View File

@ -29,6 +29,26 @@ final BuiltSet<AppLayout> _$values = new BuiltSet<AppLayout>(const <AppLayout>[
_$desktop, _$desktop,
]); ]);
const ModuleLayout _$list = const ModuleLayout._('list');
const ModuleLayout _$table = const ModuleLayout._('table');
ModuleLayout _$moduleLayoutValueOf(String name) {
switch (name) {
case 'list':
return _$list;
case 'table':
return _$table;
default:
throw new ArgumentError(name);
}
}
final BuiltSet<ModuleLayout> _$moduleLayoutValues =
new BuiltSet<ModuleLayout>(const <ModuleLayout>[
_$list,
_$table,
]);
const AppSidebar _$menu = const AppSidebar._('menu'); const AppSidebar _$menu = const AppSidebar._('menu');
const AppSidebar _$history = const AppSidebar._('history'); const AppSidebar _$history = const AppSidebar._('history');
@ -77,6 +97,8 @@ Serializer<PrefState> _$prefStateSerializer = new _$PrefStateSerializer();
Serializer<CompanyPrefState> _$companyPrefStateSerializer = Serializer<CompanyPrefState> _$companyPrefStateSerializer =
new _$CompanyPrefStateSerializer(); new _$CompanyPrefStateSerializer();
Serializer<AppLayout> _$appLayoutSerializer = new _$AppLayoutSerializer(); Serializer<AppLayout> _$appLayoutSerializer = new _$AppLayoutSerializer();
Serializer<ModuleLayout> _$moduleLayoutSerializer =
new _$ModuleLayoutSerializer();
Serializer<AppSidebar> _$appSidebarSerializer = new _$AppSidebarSerializer(); Serializer<AppSidebar> _$appSidebarSerializer = new _$AppSidebarSerializer();
Serializer<AppSidebarMode> _$appSidebarModeSerializer = Serializer<AppSidebarMode> _$appSidebarModeSerializer =
new _$AppSidebarModeSerializer(); new _$AppSidebarModeSerializer();
@ -93,9 +115,12 @@ class _$PrefStateSerializer implements StructuredSerializer<PrefState> {
Iterable<Object> serialize(Serializers serializers, PrefState object, Iterable<Object> serialize(Serializers serializers, PrefState object,
{FullType specifiedType = FullType.unspecified}) { {FullType specifiedType = FullType.unspecified}) {
final result = <Object>[ final result = <Object>[
'layout', 'appLayout',
serializers.serialize(object.layout, serializers.serialize(object.appLayout,
specifiedType: const FullType(AppLayout)), specifiedType: const FullType(AppLayout)),
'moduleLayout',
serializers.serialize(object.moduleLayout,
specifiedType: const FullType(ModuleLayout)),
'menuSidebarMode', 'menuSidebarMode',
serializers.serialize(object.menuSidebarMode, serializers.serialize(object.menuSidebarMode,
specifiedType: const FullType(AppSidebarMode)), specifiedType: const FullType(AppSidebarMode)),
@ -146,10 +171,14 @@ class _$PrefStateSerializer implements StructuredSerializer<PrefState> {
iterator.moveNext(); iterator.moveNext();
final dynamic value = iterator.current; final dynamic value = iterator.current;
switch (key) { switch (key) {
case 'layout': case 'appLayout':
result.layout = serializers.deserialize(value, result.appLayout = serializers.deserialize(value,
specifiedType: const FullType(AppLayout)) as AppLayout; specifiedType: const FullType(AppLayout)) as AppLayout;
break; break;
case 'moduleLayout':
result.moduleLayout = serializers.deserialize(value,
specifiedType: const FullType(ModuleLayout)) as ModuleLayout;
break;
case 'menuSidebarMode': case 'menuSidebarMode':
result.menuSidebarMode = serializers.deserialize(value, result.menuSidebarMode = serializers.deserialize(value,
specifiedType: const FullType(AppSidebarMode)) as AppSidebarMode; specifiedType: const FullType(AppSidebarMode)) as AppSidebarMode;
@ -272,6 +301,23 @@ class _$AppLayoutSerializer implements PrimitiveSerializer<AppLayout> {
AppLayout.valueOf(serialized as String); AppLayout.valueOf(serialized as String);
} }
class _$ModuleLayoutSerializer implements PrimitiveSerializer<ModuleLayout> {
@override
final Iterable<Type> types = const <Type>[ModuleLayout];
@override
final String wireName = 'ModuleLayout';
@override
Object serialize(Serializers serializers, ModuleLayout object,
{FullType specifiedType = FullType.unspecified}) =>
object.name;
@override
ModuleLayout deserialize(Serializers serializers, Object serialized,
{FullType specifiedType = FullType.unspecified}) =>
ModuleLayout.valueOf(serialized as String);
}
class _$AppSidebarSerializer implements PrimitiveSerializer<AppSidebar> { class _$AppSidebarSerializer implements PrimitiveSerializer<AppSidebar> {
@override @override
final Iterable<Type> types = const <Type>[AppSidebar]; final Iterable<Type> types = const <Type>[AppSidebar];
@ -363,7 +409,9 @@ class _$HistoryRecordSerializer implements StructuredSerializer<HistoryRecord> {
class _$PrefState extends PrefState { class _$PrefState extends PrefState {
@override @override
final AppLayout layout; final AppLayout appLayout;
@override
final ModuleLayout moduleLayout;
@override @override
final AppSidebarMode menuSidebarMode; final AppSidebarMode menuSidebarMode;
@override @override
@ -391,7 +439,8 @@ class _$PrefState extends PrefState {
(new PrefStateBuilder()..update(updates)).build(); (new PrefStateBuilder()..update(updates)).build();
_$PrefState._( _$PrefState._(
{this.layout, {this.appLayout,
this.moduleLayout,
this.menuSidebarMode, this.menuSidebarMode,
this.historySidebarMode, this.historySidebarMode,
this.isMenuVisible, this.isMenuVisible,
@ -404,8 +453,11 @@ class _$PrefState extends PrefState {
this.addDocumentsToInvoice, this.addDocumentsToInvoice,
this.companyPrefs}) this.companyPrefs})
: super._() { : super._() {
if (layout == null) { if (appLayout == null) {
throw new BuiltValueNullFieldError('PrefState', 'layout'); throw new BuiltValueNullFieldError('PrefState', 'appLayout');
}
if (moduleLayout == null) {
throw new BuiltValueNullFieldError('PrefState', 'moduleLayout');
} }
if (menuSidebarMode == null) { if (menuSidebarMode == null) {
throw new BuiltValueNullFieldError('PrefState', 'menuSidebarMode'); throw new BuiltValueNullFieldError('PrefState', 'menuSidebarMode');
@ -454,7 +506,8 @@ class _$PrefState extends PrefState {
bool operator ==(Object other) { bool operator ==(Object other) {
if (identical(other, this)) return true; if (identical(other, this)) return true;
return other is PrefState && return other is PrefState &&
layout == other.layout && appLayout == other.appLayout &&
moduleLayout == other.moduleLayout &&
menuSidebarMode == other.menuSidebarMode && menuSidebarMode == other.menuSidebarMode &&
historySidebarMode == other.historySidebarMode && historySidebarMode == other.historySidebarMode &&
isMenuVisible == other.isMenuVisible && isMenuVisible == other.isMenuVisible &&
@ -480,7 +533,9 @@ class _$PrefState extends PrefState {
$jc( $jc(
$jc( $jc(
$jc( $jc(
$jc($jc(0, layout.hashCode), $jc(
$jc($jc(0, appLayout.hashCode),
moduleLayout.hashCode),
menuSidebarMode.hashCode), menuSidebarMode.hashCode),
historySidebarMode.hashCode), historySidebarMode.hashCode),
isMenuVisible.hashCode), isMenuVisible.hashCode),
@ -497,7 +552,8 @@ class _$PrefState extends PrefState {
@override @override
String toString() { String toString() {
return (newBuiltValueToStringHelper('PrefState') return (newBuiltValueToStringHelper('PrefState')
..add('layout', layout) ..add('appLayout', appLayout)
..add('moduleLayout', moduleLayout)
..add('menuSidebarMode', menuSidebarMode) ..add('menuSidebarMode', menuSidebarMode)
..add('historySidebarMode', historySidebarMode) ..add('historySidebarMode', historySidebarMode)
..add('isMenuVisible', isMenuVisible) ..add('isMenuVisible', isMenuVisible)
@ -516,9 +572,14 @@ class _$PrefState extends PrefState {
class PrefStateBuilder implements Builder<PrefState, PrefStateBuilder> { class PrefStateBuilder implements Builder<PrefState, PrefStateBuilder> {
_$PrefState _$v; _$PrefState _$v;
AppLayout _layout; AppLayout _appLayout;
AppLayout get layout => _$this._layout; AppLayout get appLayout => _$this._appLayout;
set layout(AppLayout layout) => _$this._layout = layout; set appLayout(AppLayout appLayout) => _$this._appLayout = appLayout;
ModuleLayout _moduleLayout;
ModuleLayout get moduleLayout => _$this._moduleLayout;
set moduleLayout(ModuleLayout moduleLayout) =>
_$this._moduleLayout = moduleLayout;
AppSidebarMode _menuSidebarMode; AppSidebarMode _menuSidebarMode;
AppSidebarMode get menuSidebarMode => _$this._menuSidebarMode; AppSidebarMode get menuSidebarMode => _$this._menuSidebarMode;
@ -579,7 +640,8 @@ class PrefStateBuilder implements Builder<PrefState, PrefStateBuilder> {
PrefStateBuilder get _$this { PrefStateBuilder get _$this {
if (_$v != null) { if (_$v != null) {
_layout = _$v.layout; _appLayout = _$v.appLayout;
_moduleLayout = _$v.moduleLayout;
_menuSidebarMode = _$v.menuSidebarMode; _menuSidebarMode = _$v.menuSidebarMode;
_historySidebarMode = _$v.historySidebarMode; _historySidebarMode = _$v.historySidebarMode;
_isMenuVisible = _$v.isMenuVisible; _isMenuVisible = _$v.isMenuVisible;
@ -615,7 +677,8 @@ class PrefStateBuilder implements Builder<PrefState, PrefStateBuilder> {
try { try {
_$result = _$v ?? _$result = _$v ??
new _$PrefState._( new _$PrefState._(
layout: layout, appLayout: appLayout,
moduleLayout: moduleLayout,
menuSidebarMode: menuSidebarMode, menuSidebarMode: menuSidebarMode,
historySidebarMode: historySidebarMode, historySidebarMode: historySidebarMode,
isMenuVisible: isMenuVisible, isMenuVisible: isMenuVisible,

View File

@ -1,8 +1,11 @@
import 'package:built_collection/built_collection.dart'; import 'package:built_collection/built_collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart'; import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:invoiceninja_flutter/redux/ui/pref_state.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_state.dart';
import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:redux/redux.dart'; import 'package:redux/redux.dart';
@ -260,11 +263,20 @@ class _AppBottomBarState extends State<AppBottomBar> {
return StoreBuilder(builder: (BuildContext context, Store<AppState> store) { return StoreBuilder(builder: (BuildContext context, Store<AppState> store) {
final localization = AppLocalization.of(context); final localization = AppLocalization.of(context);
final prefState = store.state.prefState;
final isList = prefState.moduleLayout == ModuleLayout.list;
return BottomAppBar( return BottomAppBar(
shape: CircularNotchedRectangle(), shape: CircularNotchedRectangle(),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
IconButton(
tooltip: AppLocalization.of(context).switchListTable,
icon: Icon(isList ? Icons.table_chart : Icons.view_list),
onPressed: () {
store.dispatch(SwitchListTableLayout());
},
),
if (widget.sortFields.isNotEmpty) if (widget.sortFields.isNotEmpty)
IconButton( IconButton(
tooltip: AppLocalization.of(context).sort, tooltip: AppLocalization.of(context).sort,

View File

@ -53,7 +53,7 @@ class _DeviceSettingsState extends State<DeviceSettings> {
children: <Widget>[ children: <Widget>[
AppDropdownButton<AppLayout>( AppDropdownButton<AppLayout>(
labelText: localization.layout, labelText: localization.layout,
value: viewModel.state.prefState.layout, value: viewModel.state.prefState.appLayout,
onChanged: (dynamic value) => onChanged: (dynamic value) =>
viewModel.onLayoutChanged(context, value), viewModel.onLayoutChanged(context, value),
items: [ items: [
@ -67,7 +67,7 @@ class _DeviceSettingsState extends State<DeviceSettings> {
), ),
], ],
), ),
if (state.prefState.layout == AppLayout.tablet) ...[ if (state.prefState.appLayout == AppLayout.tablet) ...[
AppDropdownButton<AppSidebarMode>( AppDropdownButton<AppSidebarMode>(
labelText: localization.menuSidebar, labelText: localization.menuSidebar,
value: state.prefState.menuSidebarMode, value: state.prefState.menuSidebarMode,

View File

@ -814,7 +814,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
'default_tax_rate_3': 'Default Tax Rate 3', 'default_tax_rate_3': 'Default Tax Rate 3',
'email_subject_invoice': 'Email Invoice Subject', 'email_subject_invoice': 'Email Invoice Subject',
'email_subject_quote': 'Email Quote Subject', 'email_subject_quote': 'Email Quote Subject',
'email_subject_payment': 'Email Payment Subject' 'email_subject_payment': 'Email Payment Subject',
'switch_list_table': 'Switch List Table'
}, },
'sq': { 'sq': {
'thank_you_for_your_purchase': 'Thank you for your purchase!', 'thank_you_for_your_purchase': 'Thank you for your purchase!',
@ -15766,6 +15767,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get newPayment => _localizedValues[localeCode]['new_payment']; String get newPayment => _localizedValues[localeCode]['new_payment'];
String get switchListTable => _localizedValues[localeCode]['switch_list_table'];
String lookup(String key) { String lookup(String key) {
final lookupKey = toSnakeCase(key); final lookupKey = toSnakeCase(key);
return _localizedValues[localeCode][lookupKey] ?? return _localizedValues[localeCode][lookupKey] ??

View File

@ -33,7 +33,7 @@ AppLayout calculateLayout(BuildContext context) {
} }
AppLayout getLayout(BuildContext context) => AppLayout getLayout(BuildContext context) =>
StoreProvider.of<AppState>(context).state.prefState.layout ?? StoreProvider.of<AppState>(context).state.prefState.appLayout ??
AppLayout.mobile; AppLayout.mobile;
bool isMobile(BuildContext context) => getLayout(context) == AppLayout.mobile; bool isMobile(BuildContext context) => getLayout(context) == AppLayout.mobile;