Add drawer animation

This commit is contained in:
Hillel Coren 2020-05-22 15:39:50 +03:00
parent 26e595755d
commit 6f855ee121
17 changed files with 95 additions and 45 deletions

View File

@ -79,8 +79,8 @@ class LoadStaticSuccess implements PersistStatic {
final StaticDataEntity data; final StaticDataEntity data;
} }
class UserSettingsChanged implements PersistPrefs { class UserPreferencesChanged implements PersistPrefs {
UserSettingsChanged({ UserPreferencesChanged({
this.layout, this.layout,
this.sidebar, this.sidebar,
this.enableDarkMode, this.enableDarkMode,
@ -93,6 +93,8 @@ class UserSettingsChanged implements PersistPrefs {
this.accentColor, this.accentColor,
this.menuMode, this.menuMode,
this.historyMode, this.historyMode,
this.fullHeightFilter,
this.fullWidthEditor,
}); });
final AppLayout layout; final AppLayout layout;
@ -106,6 +108,8 @@ class UserSettingsChanged implements PersistPrefs {
final bool autoStartTasks; final bool autoStartTasks;
final bool isPreviewVisible; final bool isPreviewVisible;
final bool addDocumentsToInvoice; final bool addDocumentsToInvoice;
final bool fullWidthEditor;
final bool fullHeightFilter;
final String accentColor; final String accentColor;
} }
@ -350,7 +354,7 @@ void viewEntityById({
if (!state.prefState.isPreviewVisible && if (!state.prefState.isPreviewVisible &&
state.prefState.moduleLayout == ModuleLayout.table) { state.prefState.moduleLayout == ModuleLayout.table) {
store.dispatch(UserSettingsChanged(isPreviewVisible: true)); store.dispatch(UserPreferencesChanged(isPreviewVisible: true));
} }
switch (entityType) { switch (entityType) {

View File

@ -261,7 +261,7 @@ Middleware<AppState> _createLoadState(
completer.future.then((_) { completer.future.then((_) {
final layout = calculateLayout(action.context); final layout = calculateLayout(action.context);
if (store.state.prefState.isNotMobile && layout == AppLayout.mobile) { if (store.state.prefState.isNotMobile && layout == AppLayout.mobile) {
store.dispatch(UserSettingsChanged(layout: layout)); store.dispatch(UserPreferencesChanged(layout: layout));
AppBuilder.of(action.context).rebuild(); AppBuilder.of(action.context).rebuild();
WidgetsBinding.instance.addPostFrameCallback((duration) { WidgetsBinding.instance.addPostFrameCallback((duration) {
store.dispatch( store.dispatch(

View File

@ -54,10 +54,10 @@ PrefState prefReducer(
} }
Reducer<bool> menuVisibleReducer = combineReducers([ Reducer<bool> menuVisibleReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((value, action) { TypedReducer<bool, UserPreferencesChanged>((value, action) {
return action.sidebar == AppSidebar.menu ? !value : value; return action.sidebar == AppSidebar.menu ? !value : value;
}), }),
TypedReducer<bool, UserSettingsChanged>((value, action) { TypedReducer<bool, UserPreferencesChanged>((value, action) {
switch (action.menuMode) { switch (action.menuMode) {
case AppSidebarMode.visible: case AppSidebarMode.visible:
return true; return true;
@ -71,10 +71,10 @@ Reducer<bool> menuVisibleReducer = combineReducers([
]); ]);
Reducer<bool> historyVisibleReducer = combineReducers([ Reducer<bool> historyVisibleReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((value, action) { TypedReducer<bool, UserPreferencesChanged>((value, action) {
return action.sidebar == AppSidebar.history ? !value : value; return action.sidebar == AppSidebar.history ? !value : value;
}), }),
TypedReducer<bool, UserSettingsChanged>((value, action) { TypedReducer<bool, UserPreferencesChanged>((value, action) {
return action.historyMode == AppSidebarMode.visible return action.historyMode == AppSidebarMode.visible
? true ? true
: action.historyMode == AppSidebarMode.float ? false : value; : action.historyMode == AppSidebarMode.float ? false : value;
@ -96,7 +96,7 @@ Reducer<int> filterClearedAtReducer = combineReducers([
]); ]);
Reducer<AppLayout> layoutReducer = combineReducers([ Reducer<AppLayout> layoutReducer = combineReducers([
TypedReducer<AppLayout, UserSettingsChanged>((layout, action) { TypedReducer<AppLayout, UserPreferencesChanged>((layout, action) {
return action.layout ?? layout; return action.layout ?? layout;
}), }),
]); ]);
@ -112,56 +112,56 @@ Reducer<ModuleLayout> moduleLayoutReducer = combineReducers([
]); ]);
Reducer<AppSidebarMode> manuSidebarReducer = combineReducers([ Reducer<AppSidebarMode> manuSidebarReducer = combineReducers([
TypedReducer<AppSidebarMode, UserSettingsChanged>((mode, action) { TypedReducer<AppSidebarMode, UserPreferencesChanged>((mode, action) {
return action.menuMode ?? mode; return action.menuMode ?? mode;
}), }),
]); ]);
Reducer<AppSidebarMode> historySidebarReducer = combineReducers([ Reducer<AppSidebarMode> historySidebarReducer = combineReducers([
TypedReducer<AppSidebarMode, UserSettingsChanged>((mode, action) { TypedReducer<AppSidebarMode, UserPreferencesChanged>((mode, action) {
return action.historyMode ?? mode; return action.historyMode ?? mode;
}), }),
]); ]);
Reducer<bool> emailPaymentReducer = combineReducers([ Reducer<bool> emailPaymentReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((emailPayment, action) { TypedReducer<bool, UserPreferencesChanged>((emailPayment, action) {
return action.emailPayment ?? emailPayment; return action.emailPayment ?? emailPayment;
}), }),
]); ]);
Reducer<bool> darkModeReducer = combineReducers([ Reducer<bool> darkModeReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((enableDarkMode, action) { TypedReducer<bool, UserPreferencesChanged>((enableDarkMode, action) {
return action.enableDarkMode ?? enableDarkMode; return action.enableDarkMode ?? enableDarkMode;
}), }),
]); ]);
Reducer<bool> longPressReducer = combineReducers([ Reducer<bool> longPressReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>( TypedReducer<bool, UserPreferencesChanged>(
(longPressSelectionIsDefault, action) { (longPressSelectionIsDefault, action) {
return action.longPressSelectionIsDefault ?? longPressSelectionIsDefault; return action.longPressSelectionIsDefault ?? longPressSelectionIsDefault;
}), }),
]); ]);
Reducer<bool> autoStartTasksReducer = combineReducers([ Reducer<bool> autoStartTasksReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((autoStartTasks, action) { TypedReducer<bool, UserPreferencesChanged>((autoStartTasks, action) {
return action.autoStartTasks ?? autoStartTasks; return action.autoStartTasks ?? autoStartTasks;
}), }),
]); ]);
Reducer<bool> isPreviewVisibleReducer = combineReducers([ Reducer<bool> isPreviewVisibleReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((isPreviewVisible, action) { TypedReducer<bool, UserPreferencesChanged>((isPreviewVisible, action) {
return action.isPreviewVisible ?? isPreviewVisible; return action.isPreviewVisible ?? isPreviewVisible;
}), }),
]); ]);
Reducer<bool> addDocumentsToInvoiceReducer = combineReducers([ Reducer<bool> addDocumentsToInvoiceReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((addDocumentsToInvoice, action) { TypedReducer<bool, UserPreferencesChanged>((addDocumentsToInvoice, action) {
return action.addDocumentsToInvoice ?? addDocumentsToInvoice; return action.addDocumentsToInvoice ?? addDocumentsToInvoice;
}), }),
]); ]);
Reducer<bool> requireAuthenticationReducer = combineReducers([ Reducer<bool> requireAuthenticationReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((requireAuthentication, action) { TypedReducer<bool, UserPreferencesChanged>((requireAuthentication, action) {
return action.requireAuthentication ?? requireAuthentication; return action.requireAuthentication ?? requireAuthentication;
}), }),
]); ]);

View File

@ -360,7 +360,7 @@ class _AppBottomBarState extends State<AppBottomBar> {
tooltip: localization.preview, tooltip: localization.preview,
icon: Icon(Icons.chrome_reader_mode), icon: Icon(Icons.chrome_reader_mode),
onPressed: () { onPressed: () {
store.dispatch(UserSettingsChanged( store.dispatch(UserPreferencesChanged(
isPreviewVisible: !state.prefState.isPreviewVisible)); isPreviewVisible: !state.prefState.isPreviewVisible));
}, },
), ),

View File

@ -67,7 +67,7 @@ class HistoryDrawer extends StatelessWidget {
), ),
onPressed: () { onPressed: () {
store.dispatch( store.dispatch(
UserSettingsChanged(sidebar: AppSidebar.history)); UserPreferencesChanged(sidebar: AppSidebar.history));
}, },
) )
], ],

View File

@ -126,7 +126,7 @@ class ListScaffold extends StatelessWidget {
Scaffold.of(context).openEndDrawer(); Scaffold.of(context).openEndDrawer();
} else { } else {
store.dispatch( store.dispatch(
UserSettingsChanged(sidebar: AppSidebar.history)); UserPreferencesChanged(sidebar: AppSidebar.history));
} }
}, },
), ),

View File

@ -260,6 +260,8 @@ class MainScreen extends StatelessWidget {
child: FocusTraversalGroup( child: FocusTraversalGroup(
policy: WidgetOrderTraversalPolicy(), policy: WidgetOrderTraversalPolicy(),
child: ChangeLayoutBanner( child: ChangeLayoutBanner(
key: ValueKey(prefState.appLayout),
appLayout: prefState.appLayout,
child: Row(children: <Widget>[ child: Row(children: <Widget>[
if (prefState.showMenu) ...[ if (prefState.showMenu) ...[
MenuDrawerBuilder(), MenuDrawerBuilder(),
@ -584,9 +586,14 @@ class _CustomDivider extends StatelessWidget {
} }
class ChangeLayoutBanner extends StatefulWidget { 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 Widget child;
final AppLayout appLayout;
@override @override
_ChangeLayoutBannerState createState() => _ChangeLayoutBannerState(); _ChangeLayoutBannerState createState() => _ChangeLayoutBannerState();
@ -600,14 +607,14 @@ class _ChangeLayoutBannerState extends State<ChangeLayoutBanner> {
final store = StoreProvider.of<AppState>(context); final store = StoreProvider.of<AppState>(context);
final localization = AppLocalization.of(context); final localization = AppLocalization.of(context);
final layout = store.state.prefState.appLayout;
final calculatedLayout = calculateLayout(context, breakOutTablet: true); final calculatedLayout = calculateLayout(context, breakOutTablet: true);
String message; String message;
if (!_dismissedChange) { if (!_dismissedChange) {
if (layout == AppLayout.mobile && calculatedLayout == AppLayout.desktop) { if (widget.appLayout == AppLayout.mobile &&
calculatedLayout == AppLayout.desktop) {
message = localization.changeToDekstopLayout; message = localization.changeToDekstopLayout;
} else if (layout == AppLayout.desktop && } else if (widget.appLayout == AppLayout.desktop &&
calculatedLayout == AppLayout.mobile) { calculatedLayout == AppLayout.mobile) {
message = localization.changeToMobileLayout; message = localization.changeToMobileLayout;
} }
@ -635,7 +642,7 @@ class _ChangeLayoutBannerState extends State<ChangeLayoutBanner> {
child: Text(localization.change.toUpperCase()), child: Text(localization.change.toUpperCase()),
onPressed: () { onPressed: () {
store.dispatch( store.dispatch(
UserSettingsChanged(layout: AppLayout.mobile)); UserPreferencesChanged(layout: AppLayout.mobile));
AppBuilder.of(context).rebuild(); AppBuilder.of(context).rebuild();
WidgetsBinding.instance.addPostFrameCallback((duration) { WidgetsBinding.instance.addPostFrameCallback((duration) {
store.dispatch(ViewDashboard( store.dispatch(ViewDashboard(

View File

@ -610,7 +610,7 @@ class SidebarFooter extends StatelessWidget {
icon: Icon(Icons.chevron_left), icon: Icon(Icons.chevron_left),
onPressed: () { onPressed: () {
store.dispatch( store.dispatch(
UserSettingsChanged(sidebar: AppSidebar.menu)); UserPreferencesChanged(sidebar: AppSidebar.menu));
}, },
), ),
), ),
@ -696,7 +696,7 @@ class SidebarFooterCollapsed extends StatelessWidget {
icon: Icon(Icons.chevron_right), icon: Icon(Icons.chevron_right),
tooltip: localization.showMenu, tooltip: localization.showMenu,
onPressed: () { onPressed: () {
store.dispatch(UserSettingsChanged(sidebar: AppSidebar.menu)); store.dispatch(UserPreferencesChanged(sidebar: AppSidebar.menu));
}, },
), ),
); );

View File

@ -93,7 +93,7 @@ class LoginVM {
void _handleLogin(BuildContext context) { void _handleLogin(BuildContext context) {
final layout = calculateLayout(context); final layout = calculateLayout(context);
store.dispatch(UserSettingsChanged(layout: layout)); store.dispatch(UserPreferencesChanged(layout: layout));
AppBuilder.of(context).rebuild(); AppBuilder.of(context).rebuild();
WidgetsBinding.instance.addPostFrameCallback((duration) { WidgetsBinding.instance.addPostFrameCallback((duration) {

View File

@ -77,7 +77,7 @@ class _DashboardScreenState extends State<DashboardScreen>
Scaffold.of(context).openEndDrawer(); Scaffold.of(context).openEndDrawer();
} else { } else {
store.dispatch( store.dispatch(
UserSettingsChanged(sidebar: AppSidebar.history)); UserPreferencesChanged(sidebar: AppSidebar.history));
} }
}, },
), ),

View File

@ -133,7 +133,7 @@ class ExpenseEditVM {
} }
final SharedPreferences prefs = await SharedPreferences.getInstance(); final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool(kSharedPrefEmailPayment, value); prefs.setBool(kSharedPrefEmailPayment, value);
store.dispatch(UserSettingsChanged(addDocumentsToInvoice: value)); store.dispatch(UserPreferencesChanged(addDocumentsToInvoice: value));
}, },
); );
} }

View File

@ -74,7 +74,7 @@ class PaymentEditVM {
} }
final SharedPreferences prefs = await SharedPreferences.getInstance(); final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool(kSharedPrefEmailPayment, value); prefs.setBool(kSharedPrefEmailPayment, value);
store.dispatch(UserSettingsChanged(emailPayment: value)); store.dispatch(UserPreferencesChanged(emailPayment: value));
}, },
onCancelPressed: (BuildContext context) { onCancelPressed: (BuildContext context) {
createEntity(context: context, entity: PaymentEntity(), force: true); createEntity(context: context, entity: PaymentEntity(), force: true);

View File

@ -78,7 +78,7 @@ class PaymentRefundVM {
onEmailChanged: (value) async { onEmailChanged: (value) async {
final SharedPreferences prefs = await SharedPreferences.getInstance(); final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool(kSharedPrefEmailPayment, value); prefs.setBool(kSharedPrefEmailPayment, value);
store.dispatch(UserSettingsChanged(emailPayment: value)); store.dispatch(UserPreferencesChanged(emailPayment: value));
}, },
onCancelPressed: (BuildContext context) { onCancelPressed: (BuildContext context) {
createEntity(context: context, entity: PaymentEntity(), force: true); createEntity(context: context, entity: PaymentEntity(), force: true);

View File

@ -119,7 +119,7 @@ class ReportsScreen extends StatelessWidget {
Scaffold.of(context).openEndDrawer(); Scaffold.of(context).openEndDrawer();
} else { } else {
store.dispatch( store.dispatch(
UserSettingsChanged(sidebar: AppSidebar.history)); UserPreferencesChanged(sidebar: AppSidebar.history));
} }
}, },
), ),

View File

@ -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/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';
import 'package:invoiceninja_flutter/ui/settings/device_settings_list_vm.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/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart';
@ -106,10 +107,30 @@ class _DeviceSettingsState extends State<DeviceSettings> {
], ],
], ],
), ),
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( FormCard(
children: <Widget>[ children: <Widget>[
SwitchListTile( SwitchListTile(
title: Text(AppLocalization.of(context).darkMode), title: Text(localization.darkMode),
value: prefState.enableDarkMode, value: prefState.enableDarkMode,
onChanged: (value) => onChanged: (value) =>
viewModel.onDarkModeChanged(context, value), viewModel.onDarkModeChanged(context, value),
@ -119,8 +140,7 @@ class _DeviceSettingsState extends State<DeviceSettings> {
activeColor: Theme.of(context).accentColor, activeColor: Theme.of(context).accentColor,
), ),
SwitchListTile( SwitchListTile(
title: Text(AppLocalization.of(context) title: Text(localization.longPressSelectionIsDefault),
.longPressSelectionIsDefault),
value: prefState.longPressSelectionIsDefault, value: prefState.longPressSelectionIsDefault,
onChanged: (value) => onChanged: (value) =>
viewModel.onLongPressSelectionIsDefault(context, value), viewModel.onLongPressSelectionIsDefault(context, value),

View File

@ -46,6 +46,8 @@ class DeviceSettingsVM {
@required this.authenticationSupported, @required this.authenticationSupported,
@required this.onMenuModeChanged, @required this.onMenuModeChanged,
@required this.onHistoryModeChanged, @required this.onHistoryModeChanged,
@required this.onFullHeightFilterChanged,
@required this.onFullWidthEditorChanged,
}); });
static DeviceSettingsVM fromStore(Store<AppState> store) { static DeviceSettingsVM fromStore(Store<AppState> store) {
@ -76,26 +78,33 @@ class DeviceSettingsVM {
callback: () => store.dispatch(UserLogout(context))), callback: () => store.dispatch(UserLogout(context))),
onRefreshTap: (BuildContext context) => _refreshData(context), onRefreshTap: (BuildContext context) => _refreshData(context),
onDarkModeChanged: (BuildContext context, bool value) async { onDarkModeChanged: (BuildContext context, bool value) async {
store.dispatch(UserSettingsChanged(enableDarkMode: value)); store.dispatch(UserPreferencesChanged(enableDarkMode: value));
AppBuilder.of(context).rebuild(); AppBuilder.of(context).rebuild();
}, },
onAutoStartTasksChanged: (BuildContext context, bool value) async { onAutoStartTasksChanged: (BuildContext context, bool value) async {
store.dispatch(UserSettingsChanged(autoStartTasks: value)); store.dispatch(UserPreferencesChanged(autoStartTasks: value));
}, },
onLongPressSelectionIsDefault: (BuildContext context, bool value) async { onLongPressSelectionIsDefault: (BuildContext context, bool value) async {
store.dispatch(UserSettingsChanged(longPressSelectionIsDefault: value)); store.dispatch(
UserPreferencesChanged(longPressSelectionIsDefault: value));
}, },
onMenuModeChanged: (context, value) async { onMenuModeChanged: (context, value) async {
store.dispatch(UserSettingsChanged(menuMode: value)); store.dispatch(UserPreferencesChanged(menuMode: value));
}, },
onHistoryModeChanged: (context, value) async { 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 { onLayoutChanged: (BuildContext context, AppLayout value) async {
if (store.state.prefState.appLayout == value) { if (store.state.prefState.appLayout == value) {
return; return;
} }
store.dispatch(UserSettingsChanged(layout: value)); store.dispatch(UserPreferencesChanged(layout: value));
AppBuilder.of(context).rebuild(); AppBuilder.of(context).rebuild();
WidgetsBinding.instance.addPostFrameCallback((duration) { WidgetsBinding.instance.addPostFrameCallback((duration) {
if (value == AppLayout.mobile) { if (value == AppLayout.mobile) {
@ -119,7 +128,7 @@ class DeviceSettingsVM {
print(e); print(e);
} }
if (authenticated) { if (authenticated) {
store.dispatch(UserSettingsChanged(requireAuthentication: value)); store.dispatch(UserPreferencesChanged(requireAuthentication: value));
} else {} } else {}
}, },
//authenticationSupported: LocalAuthentication().canCheckBiometrics, //authenticationSupported: LocalAuthentication().canCheckBiometrics,
@ -140,6 +149,8 @@ class DeviceSettingsVM {
final AppState state; final AppState state;
final Function(BuildContext) onLogoutTap; final Function(BuildContext) onLogoutTap;
final Function(BuildContext) onRefreshTap; final Function(BuildContext) onRefreshTap;
final Function(BuildContext, bool) onFullHeightFilterChanged;
final Function(BuildContext, bool) onFullWidthEditorChanged;
final Function(BuildContext, bool) onDarkModeChanged; final Function(BuildContext, bool) onDarkModeChanged;
final Function(BuildContext, AppLayout) onLayoutChanged; final Function(BuildContext, AppLayout) onLayoutChanged;
final Function(BuildContext, AppSidebarMode) onMenuModeChanged; final Function(BuildContext, AppSidebarMode) onMenuModeChanged;

View File

@ -15,6 +15,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = { static final Map<String, Map<String, String>> _localizedValues = {
'en': { 'en': {
// STARTER: lang key - do not remove comment // 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', 'email_sign_in': 'Sign in with email',
'change': 'Change', 'change': 'Change',
'change_to_mobile_layout': 'Change to the mobile layout?', '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 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) { String lookup(String key) {
final lookupKey = toSnakeCase(key); final lookupKey = toSnakeCase(key);
return _localizedValues[localeCode][lookupKey] ?? return _localizedValues[localeCode][lookupKey] ??