diff --git a/lib/redux/app/app_actions.dart b/lib/redux/app/app_actions.dart index a8059ca34..492eb87d0 100644 --- a/lib/redux/app/app_actions.dart +++ b/lib/redux/app/app_actions.dart @@ -79,8 +79,8 @@ class LoadStaticSuccess implements PersistStatic { final StaticDataEntity data; } -class UserSettingsChanged implements PersistPrefs { - UserSettingsChanged({ +class UserPreferencesChanged implements PersistPrefs { + UserPreferencesChanged({ this.layout, this.sidebar, this.enableDarkMode, @@ -93,6 +93,8 @@ class UserSettingsChanged implements PersistPrefs { this.accentColor, this.menuMode, this.historyMode, + this.fullHeightFilter, + this.fullWidthEditor, }); final AppLayout layout; @@ -106,6 +108,8 @@ class UserSettingsChanged implements PersistPrefs { final bool autoStartTasks; final bool isPreviewVisible; final bool addDocumentsToInvoice; + final bool fullWidthEditor; + final bool fullHeightFilter; final String accentColor; } @@ -350,7 +354,7 @@ void viewEntityById({ if (!state.prefState.isPreviewVisible && state.prefState.moduleLayout == ModuleLayout.table) { - store.dispatch(UserSettingsChanged(isPreviewVisible: true)); + store.dispatch(UserPreferencesChanged(isPreviewVisible: true)); } switch (entityType) { diff --git a/lib/redux/app/app_middleware.dart b/lib/redux/app/app_middleware.dart index 4d5171ff3..dbb84fbe2 100644 --- a/lib/redux/app/app_middleware.dart +++ b/lib/redux/app/app_middleware.dart @@ -261,7 +261,7 @@ Middleware _createLoadState( completer.future.then((_) { final layout = calculateLayout(action.context); if (store.state.prefState.isNotMobile && layout == AppLayout.mobile) { - store.dispatch(UserSettingsChanged(layout: layout)); + store.dispatch(UserPreferencesChanged(layout: layout)); AppBuilder.of(action.context).rebuild(); WidgetsBinding.instance.addPostFrameCallback((duration) { store.dispatch( diff --git a/lib/redux/ui/pref_reducer.dart b/lib/redux/ui/pref_reducer.dart index 1ea9efd9c..1a3300a12 100644 --- a/lib/redux/ui/pref_reducer.dart +++ b/lib/redux/ui/pref_reducer.dart @@ -54,10 +54,10 @@ PrefState prefReducer( } Reducer menuVisibleReducer = combineReducers([ - TypedReducer((value, action) { + TypedReducer((value, action) { return action.sidebar == AppSidebar.menu ? !value : value; }), - TypedReducer((value, action) { + TypedReducer((value, action) { switch (action.menuMode) { case AppSidebarMode.visible: return true; @@ -71,10 +71,10 @@ Reducer menuVisibleReducer = combineReducers([ ]); Reducer historyVisibleReducer = combineReducers([ - TypedReducer((value, action) { + TypedReducer((value, action) { return action.sidebar == AppSidebar.history ? !value : value; }), - TypedReducer((value, action) { + TypedReducer((value, action) { return action.historyMode == AppSidebarMode.visible ? true : action.historyMode == AppSidebarMode.float ? false : value; @@ -96,7 +96,7 @@ Reducer filterClearedAtReducer = combineReducers([ ]); Reducer layoutReducer = combineReducers([ - TypedReducer((layout, action) { + TypedReducer((layout, action) { return action.layout ?? layout; }), ]); @@ -112,56 +112,56 @@ Reducer moduleLayoutReducer = combineReducers([ ]); Reducer manuSidebarReducer = combineReducers([ - TypedReducer((mode, action) { + TypedReducer((mode, action) { return action.menuMode ?? mode; }), ]); Reducer historySidebarReducer = combineReducers([ - TypedReducer((mode, action) { + TypedReducer((mode, action) { return action.historyMode ?? mode; }), ]); Reducer emailPaymentReducer = combineReducers([ - TypedReducer((emailPayment, action) { + TypedReducer((emailPayment, action) { return action.emailPayment ?? emailPayment; }), ]); Reducer darkModeReducer = combineReducers([ - TypedReducer((enableDarkMode, action) { + TypedReducer((enableDarkMode, action) { return action.enableDarkMode ?? enableDarkMode; }), ]); Reducer longPressReducer = combineReducers([ - TypedReducer( + TypedReducer( (longPressSelectionIsDefault, action) { return action.longPressSelectionIsDefault ?? longPressSelectionIsDefault; }), ]); Reducer autoStartTasksReducer = combineReducers([ - TypedReducer((autoStartTasks, action) { + TypedReducer((autoStartTasks, action) { return action.autoStartTasks ?? autoStartTasks; }), ]); Reducer isPreviewVisibleReducer = combineReducers([ - TypedReducer((isPreviewVisible, action) { + TypedReducer((isPreviewVisible, action) { return action.isPreviewVisible ?? isPreviewVisible; }), ]); Reducer addDocumentsToInvoiceReducer = combineReducers([ - TypedReducer((addDocumentsToInvoice, action) { + TypedReducer((addDocumentsToInvoice, action) { return action.addDocumentsToInvoice ?? addDocumentsToInvoice; }), ]); Reducer requireAuthenticationReducer = combineReducers([ - TypedReducer((requireAuthentication, action) { + TypedReducer((requireAuthentication, action) { return action.requireAuthentication ?? requireAuthentication; }), ]); diff --git a/lib/ui/app/app_bottom_bar.dart b/lib/ui/app/app_bottom_bar.dart index 5b4419fa8..843841a6a 100644 --- a/lib/ui/app/app_bottom_bar.dart +++ b/lib/ui/app/app_bottom_bar.dart @@ -360,7 +360,7 @@ class _AppBottomBarState extends State { tooltip: localization.preview, icon: Icon(Icons.chrome_reader_mode), onPressed: () { - store.dispatch(UserSettingsChanged( + store.dispatch(UserPreferencesChanged( isPreviewVisible: !state.prefState.isPreviewVisible)); }, ), diff --git a/lib/ui/app/history_drawer.dart b/lib/ui/app/history_drawer.dart index d3ef37953..7bb4716e5 100644 --- a/lib/ui/app/history_drawer.dart +++ b/lib/ui/app/history_drawer.dart @@ -67,7 +67,7 @@ class HistoryDrawer extends StatelessWidget { ), onPressed: () { store.dispatch( - UserSettingsChanged(sidebar: AppSidebar.history)); + UserPreferencesChanged(sidebar: AppSidebar.history)); }, ) ], diff --git a/lib/ui/app/list_scaffold.dart b/lib/ui/app/list_scaffold.dart index 4e22940bb..253499e10 100644 --- a/lib/ui/app/list_scaffold.dart +++ b/lib/ui/app/list_scaffold.dart @@ -126,7 +126,7 @@ class ListScaffold extends StatelessWidget { Scaffold.of(context).openEndDrawer(); } else { store.dispatch( - UserSettingsChanged(sidebar: AppSidebar.history)); + UserPreferencesChanged(sidebar: AppSidebar.history)); } }, ), diff --git a/lib/ui/app/main_screen.dart b/lib/ui/app/main_screen.dart index b88ac92dc..d68c3def1 100644 --- a/lib/ui/app/main_screen.dart +++ b/lib/ui/app/main_screen.dart @@ -260,6 +260,8 @@ class MainScreen extends StatelessWidget { child: FocusTraversalGroup( policy: WidgetOrderTraversalPolicy(), child: ChangeLayoutBanner( + key: ValueKey(prefState.appLayout), + appLayout: prefState.appLayout, child: Row(children: [ if (prefState.showMenu) ...[ MenuDrawerBuilder(), @@ -584,9 +586,14 @@ class _CustomDivider extends StatelessWidget { } class ChangeLayoutBanner extends StatefulWidget { - const ChangeLayoutBanner({this.child}); + const ChangeLayoutBanner({ + Key key, + @required this.child, + @required this.appLayout, + }) : super(key: key); final Widget child; + final AppLayout appLayout; @override _ChangeLayoutBannerState createState() => _ChangeLayoutBannerState(); @@ -600,14 +607,14 @@ class _ChangeLayoutBannerState extends State { final store = StoreProvider.of(context); final localization = AppLocalization.of(context); - final layout = store.state.prefState.appLayout; final calculatedLayout = calculateLayout(context, breakOutTablet: true); String message; if (!_dismissedChange) { - if (layout == AppLayout.mobile && calculatedLayout == AppLayout.desktop) { + if (widget.appLayout == AppLayout.mobile && + calculatedLayout == AppLayout.desktop) { message = localization.changeToDekstopLayout; - } else if (layout == AppLayout.desktop && + } else if (widget.appLayout == AppLayout.desktop && calculatedLayout == AppLayout.mobile) { message = localization.changeToMobileLayout; } @@ -635,7 +642,7 @@ class _ChangeLayoutBannerState extends State { child: Text(localization.change.toUpperCase()), onPressed: () { store.dispatch( - UserSettingsChanged(layout: AppLayout.mobile)); + UserPreferencesChanged(layout: AppLayout.mobile)); AppBuilder.of(context).rebuild(); WidgetsBinding.instance.addPostFrameCallback((duration) { store.dispatch(ViewDashboard( @@ -683,7 +690,7 @@ class _EntityFilter extends StatelessWidget { color: Theme.of(context).cardColor, child: AnimatedContainer( height: show ? kTopBottomBarHeight : 0, - duration: Duration(milliseconds: kDefaultAnimationDuration ), + duration: Duration(milliseconds: kDefaultAnimationDuration), curve: Curves.easeInOutCubic, child: Row( children: filterEntity == null diff --git a/lib/ui/app/menu_drawer.dart b/lib/ui/app/menu_drawer.dart index bc2875fe6..d0eefc989 100644 --- a/lib/ui/app/menu_drawer.dart +++ b/lib/ui/app/menu_drawer.dart @@ -610,7 +610,7 @@ class SidebarFooter extends StatelessWidget { icon: Icon(Icons.chevron_left), onPressed: () { store.dispatch( - UserSettingsChanged(sidebar: AppSidebar.menu)); + UserPreferencesChanged(sidebar: AppSidebar.menu)); }, ), ), @@ -696,7 +696,7 @@ class SidebarFooterCollapsed extends StatelessWidget { icon: Icon(Icons.chevron_right), tooltip: localization.showMenu, onPressed: () { - store.dispatch(UserSettingsChanged(sidebar: AppSidebar.menu)); + store.dispatch(UserPreferencesChanged(sidebar: AppSidebar.menu)); }, ), ); diff --git a/lib/ui/auth/login_vm.dart b/lib/ui/auth/login_vm.dart index d012795e6..9e5f25026 100644 --- a/lib/ui/auth/login_vm.dart +++ b/lib/ui/auth/login_vm.dart @@ -93,7 +93,7 @@ class LoginVM { void _handleLogin(BuildContext context) { final layout = calculateLayout(context); - store.dispatch(UserSettingsChanged(layout: layout)); + store.dispatch(UserPreferencesChanged(layout: layout)); AppBuilder.of(context).rebuild(); WidgetsBinding.instance.addPostFrameCallback((duration) { diff --git a/lib/ui/dashboard/dashboard_screen.dart b/lib/ui/dashboard/dashboard_screen.dart index ae03da82a..0b66d3b64 100644 --- a/lib/ui/dashboard/dashboard_screen.dart +++ b/lib/ui/dashboard/dashboard_screen.dart @@ -77,7 +77,7 @@ class _DashboardScreenState extends State Scaffold.of(context).openEndDrawer(); } else { store.dispatch( - UserSettingsChanged(sidebar: AppSidebar.history)); + UserPreferencesChanged(sidebar: AppSidebar.history)); } }, ), diff --git a/lib/ui/expense/edit/expense_edit_vm.dart b/lib/ui/expense/edit/expense_edit_vm.dart index 1b3d35da5..9f6bcd6ec 100644 --- a/lib/ui/expense/edit/expense_edit_vm.dart +++ b/lib/ui/expense/edit/expense_edit_vm.dart @@ -133,7 +133,7 @@ class ExpenseEditVM { } final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setBool(kSharedPrefEmailPayment, value); - store.dispatch(UserSettingsChanged(addDocumentsToInvoice: value)); + store.dispatch(UserPreferencesChanged(addDocumentsToInvoice: value)); }, ); } diff --git a/lib/ui/payment/edit/payment_edit_vm.dart b/lib/ui/payment/edit/payment_edit_vm.dart index bf73c684a..b3bab85db 100644 --- a/lib/ui/payment/edit/payment_edit_vm.dart +++ b/lib/ui/payment/edit/payment_edit_vm.dart @@ -74,7 +74,7 @@ class PaymentEditVM { } final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setBool(kSharedPrefEmailPayment, value); - store.dispatch(UserSettingsChanged(emailPayment: value)); + store.dispatch(UserPreferencesChanged(emailPayment: value)); }, onCancelPressed: (BuildContext context) { createEntity(context: context, entity: PaymentEntity(), force: true); diff --git a/lib/ui/payment/refund/payment_refund_vm.dart b/lib/ui/payment/refund/payment_refund_vm.dart index 460ed2f89..1ab6abfea 100644 --- a/lib/ui/payment/refund/payment_refund_vm.dart +++ b/lib/ui/payment/refund/payment_refund_vm.dart @@ -78,7 +78,7 @@ class PaymentRefundVM { onEmailChanged: (value) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setBool(kSharedPrefEmailPayment, value); - store.dispatch(UserSettingsChanged(emailPayment: value)); + store.dispatch(UserPreferencesChanged(emailPayment: value)); }, onCancelPressed: (BuildContext context) { createEntity(context: context, entity: PaymentEntity(), force: true); diff --git a/lib/ui/reports/reports_screen.dart b/lib/ui/reports/reports_screen.dart index 3aaca15b6..b1fec3cf0 100644 --- a/lib/ui/reports/reports_screen.dart +++ b/lib/ui/reports/reports_screen.dart @@ -119,7 +119,7 @@ class ReportsScreen extends StatelessWidget { Scaffold.of(context).openEndDrawer(); } else { store.dispatch( - UserSettingsChanged(sidebar: AppSidebar.history)); + UserPreferencesChanged(sidebar: AppSidebar.history)); } }, ), diff --git a/lib/ui/settings/device_settings_list.dart b/lib/ui/settings/device_settings_list.dart index 080f9dad3..fcbc41c82 100644 --- a/lib/ui/settings/device_settings_list.dart +++ b/lib/ui/settings/device_settings_list.dart @@ -7,6 +7,7 @@ import 'package:invoiceninja_flutter/redux/ui/pref_state.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/settings/device_settings_list_vm.dart'; +import 'package:invoiceninja_flutter/utils/icons.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart'; @@ -106,10 +107,30 @@ class _DeviceSettingsState extends State { ], ], ), + FormCard( + children: [ + SwitchListTile( + title: Text(localization.fullWidthEditor), + value: prefState.fullWidthEditor, + onChanged: (value) => + viewModel.onFullWidthEditorChanged(context, value), + secondary: Icon(getEntityIcon(EntityType.invoice)), + activeColor: Theme.of(context).accentColor, + ), + SwitchListTile( + title: Text(localization.fullHeightFilter), + value: prefState.fullHeightFilter, + onChanged: (value) => + viewModel.onFullHeightFilterChanged(context, value), + secondary: Icon(Icons.filter_list), + activeColor: Theme.of(context).accentColor, + ), + ], + ), FormCard( children: [ SwitchListTile( - title: Text(AppLocalization.of(context).darkMode), + title: Text(localization.darkMode), value: prefState.enableDarkMode, onChanged: (value) => viewModel.onDarkModeChanged(context, value), @@ -119,8 +140,7 @@ class _DeviceSettingsState extends State { activeColor: Theme.of(context).accentColor, ), SwitchListTile( - title: Text(AppLocalization.of(context) - .longPressSelectionIsDefault), + title: Text(localization.longPressSelectionIsDefault), value: prefState.longPressSelectionIsDefault, onChanged: (value) => viewModel.onLongPressSelectionIsDefault(context, value), diff --git a/lib/ui/settings/device_settings_list_vm.dart b/lib/ui/settings/device_settings_list_vm.dart index fd081ff23..7fa3ad79b 100644 --- a/lib/ui/settings/device_settings_list_vm.dart +++ b/lib/ui/settings/device_settings_list_vm.dart @@ -46,6 +46,8 @@ class DeviceSettingsVM { @required this.authenticationSupported, @required this.onMenuModeChanged, @required this.onHistoryModeChanged, + @required this.onFullHeightFilterChanged, + @required this.onFullWidthEditorChanged, }); static DeviceSettingsVM fromStore(Store store) { @@ -76,26 +78,33 @@ class DeviceSettingsVM { callback: () => store.dispatch(UserLogout(context))), onRefreshTap: (BuildContext context) => _refreshData(context), onDarkModeChanged: (BuildContext context, bool value) async { - store.dispatch(UserSettingsChanged(enableDarkMode: value)); + store.dispatch(UserPreferencesChanged(enableDarkMode: value)); AppBuilder.of(context).rebuild(); }, onAutoStartTasksChanged: (BuildContext context, bool value) async { - store.dispatch(UserSettingsChanged(autoStartTasks: value)); + store.dispatch(UserPreferencesChanged(autoStartTasks: value)); }, onLongPressSelectionIsDefault: (BuildContext context, bool value) async { - store.dispatch(UserSettingsChanged(longPressSelectionIsDefault: value)); + store.dispatch( + UserPreferencesChanged(longPressSelectionIsDefault: value)); }, onMenuModeChanged: (context, value) async { - store.dispatch(UserSettingsChanged(menuMode: value)); + store.dispatch(UserPreferencesChanged(menuMode: value)); }, onHistoryModeChanged: (context, value) async { - store.dispatch(UserSettingsChanged(historyMode: value)); + store.dispatch(UserPreferencesChanged(historyMode: value)); + }, + onFullHeightFilterChanged: (context, value) async { + store.dispatch(UserPreferencesChanged(fullHeightFilter: value)); + }, + onFullWidthEditorChanged: (context, value) async { + store.dispatch(UserPreferencesChanged(fullWidthEditor: value)); }, onLayoutChanged: (BuildContext context, AppLayout value) async { if (store.state.prefState.appLayout == value) { return; } - store.dispatch(UserSettingsChanged(layout: value)); + store.dispatch(UserPreferencesChanged(layout: value)); AppBuilder.of(context).rebuild(); WidgetsBinding.instance.addPostFrameCallback((duration) { if (value == AppLayout.mobile) { @@ -119,7 +128,7 @@ class DeviceSettingsVM { print(e); } if (authenticated) { - store.dispatch(UserSettingsChanged(requireAuthentication: value)); + store.dispatch(UserPreferencesChanged(requireAuthentication: value)); } else {} }, //authenticationSupported: LocalAuthentication().canCheckBiometrics, @@ -140,6 +149,8 @@ class DeviceSettingsVM { final AppState state; final Function(BuildContext) onLogoutTap; final Function(BuildContext) onRefreshTap; + final Function(BuildContext, bool) onFullHeightFilterChanged; + final Function(BuildContext, bool) onFullWidthEditorChanged; final Function(BuildContext, bool) onDarkModeChanged; final Function(BuildContext, AppLayout) onLayoutChanged; final Function(BuildContext, AppSidebarMode) onMenuModeChanged; diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index b04235e49..fec3f7394 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -15,6 +15,8 @@ mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { // STARTER: lang key - do not remove comment + 'full_width_editor': 'Full Width Editor', + 'full_height_filter': 'Full Height Filter', 'email_sign_in': 'Sign in with email', 'change': 'Change', 'change_to_mobile_layout': 'Change to the mobile layout?', @@ -36534,6 +36536,12 @@ mixin LocalizationsProvider on LocaleCodeAware { String get emailSignIn => _localizedValues[localeCode]['email_sign_in'] ?? ''; + String get fullWidthEditor => + _localizedValues[localeCode]['full_width_editor'] ?? ''; + + String get fullHeightFilter => + _localizedValues[localeCode]['full_height_filter'] ?? ''; + String lookup(String key) { final lookupKey = toSnakeCase(key); return _localizedValues[localeCode][lookupKey] ??