This commit is contained in:
Hillel Coren 2019-11-14 15:21:00 +02:00
parent 90f32e5670
commit 5363cb33ac
12 changed files with 234 additions and 24 deletions

View File

@ -23,12 +23,17 @@ const String kSharedPrefSecret = 'secret';
const String kSharedPrefToken = 'api_token';
const String kSharedPrefEnableDarkMode = 'enable_dark_mode';
const String kSharedPrefAccentColor = 'accent_color';
const String kSharedPrefLongPressSelectionIsDefault = 'long_press_multiselect';
const String kSharedPrefEmailPayment = 'email_payment';
const String kSharedPrefAutoStartTasks = 'auto_start_tasks';
const String kSharedPrefLongPressSelection = 'long_press_multiselect';
const String kSharedPrefAppVersion = 'app_version';
const String kSharedPrefRequireAuthentication = 'require_authentication';
const String kSharedPrefLayout = 'layout';
const String kSharedPrefMenuMode = 'menu_mode';
const String kSharedPrefHistoryMode = 'history_mode';
// TODO remove these
const String kSharedPrefAddDocumentsToInvoice = 'add_documents_to_invoice';
const String kSharedPrefEmailPayment = 'email_payment';
const String kSharedPrefAutoStartTasks = 'auto_start_tasks';
const String kProductPlanPro = 'v1_pro_yearly';
const String kProductPlanEnterprise2 = 'v1_enterprise_2_yearly';

View File

@ -9,6 +9,7 @@ part of 'serializers.dart';
Serializers _$serializers = (new Serializers().toBuilder()
..add(ActivityEntity.serializer)
..add(AppLayout.serializer)
..add(AppSidebarMode.serializer)
..add(AppState.serializer)
..add(AuthState.serializer)
..add(ClientEntity.serializer)

View File

@ -79,7 +79,7 @@ void main({bool isTesting = false}) async {
accentColor =
prefs.getString(kSharedPrefAccentColor) ?? kDefaultAccentColor;
longPressSelectionIsDefault =
prefs.getBool(kSharedPrefLongPressSelectionIsDefault) ?? false;
prefs.getBool(kSharedPrefLongPressSelection) ?? false;
requireAuthentication =
prefs.getBool(kSharedPrefRequireAuthentication) ?? false;
}

View File

@ -72,6 +72,8 @@ class UserSettingsChanged implements PersistUI {
this.longPressSelectionIsDefault,
this.addDocumentsToInvoice,
this.accentColor,
this.menuMode,
this.historyMode,
});
final bool enableDarkMode;
@ -81,6 +83,8 @@ class UserSettingsChanged implements PersistUI {
final bool autoStartTasks;
final bool addDocumentsToInvoice;
final String accentColor;
final AppSidebarMode menuMode;
final AppSidebarMode historyMode;
}
class LoadAccountSuccess {

View File

@ -431,13 +431,13 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
String toString() {
//return 'Custom fields [UI]: ${uiState.settingsUIState.userCompany.company.customFields}, [DB] ${selectedCompany.customFields}';
//return 'Permissions: ${uiState.userUIState.editing.id}';
//return 'Layout: ${uiState.layout}';
return 'Layout: ${uiState.layout}, menu: ${uiState.menuSidebarMode}, history: ${uiState.historySidebarMode}';
//return 'Sidebars - isMenuVisible: ${uiState.isMenuVisible}, isHistoryVisible: ${uiState.isHistoryVisible}';
//return 'Gateway: ${uiState.companyGatewayUIState.editing.feesAndLimitsMap}';
//return 'Routes: Current: ${uiState.currentRoute} Prev: ${uiState.previousRoute}';
//return 'Route: ${uiState.currentRoute}, Setting Type: ${uiState.settingsUIState.entityType}, Name: ${uiState.settingsUIState.settings.name}, Updated: ${uiState.settingsUIState.updatedAt}';
//return 'Route: ${uiState.currentRoute}, Previous: ${uiState.previousRoute}, Layout: ${uiState.layout}, Menu: ${uiState.isMenuVisible}, History: ${uiState.isHistoryVisible}';
return 'Route: ${uiState.currentRoute} Prev: ${uiState.previousRoute}';
//return 'Route: ${uiState.currentRoute} Prev: ${uiState.previousRoute}';
}
}

View File

@ -36,6 +36,8 @@ UIState uiReducer(UIState state, dynamic action) {
..selectedCompanyIndex =
selectedCompanyIndexReducer(state.selectedCompanyIndex, action)
..layout = layoutReducer(state.layout, action)
..menuSidebarMode = manuSidebarReducer(state.menuSidebarMode, action)
..historySidebarMode = historySidebarReducer(state.menuSidebarMode, action)
..isMenuVisible = menuVisibleReducer(state.isMenuVisible, action)
..isHistoryVisible = historyVisibleReducer(state.isHistoryVisible, action)
..previousRoute = state.currentRoute == currentRoute
@ -100,6 +102,18 @@ Reducer<AppLayout> layoutReducer = combineReducers([
}),
]);
Reducer<AppSidebarMode> manuSidebarReducer = combineReducers([
TypedReducer<AppSidebarMode, UserSettingsChanged>((mode, action) {
return action.menuMode ?? mode;
}),
]);
Reducer<AppSidebarMode> historySidebarReducer = combineReducers([
TypedReducer<AppSidebarMode, UserSettingsChanged>((mode, action) {
return action.historyMode ?? mode;
}),
]);
Reducer<bool> emailPaymentReducer = combineReducers([
TypedReducer<bool, UserSettingsChanged>((emailPayment, action) {
return action.emailPayment ?? emailPayment;

View File

@ -1,6 +1,7 @@
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:flutter/foundation.dart';
import 'package:invoiceninja_flutter/data/models/company_model.dart';
import 'package:invoiceninja_flutter/redux/client/client_state.dart';
import 'package:invoiceninja_flutter/redux/company/company_state.dart';
@ -30,17 +31,21 @@ part 'ui_state.g.dart';
abstract class UIState implements Built<UIState, UIStateBuilder> {
factory UIState(
CompanyEntity company, {
bool enableDarkMode,
String accentColor,
bool requireAuthentication,
bool longPressSelectionIsDefault,
AppLayout layout,
bool isTesting,
@required bool enableDarkMode,
@required String accentColor,
@required bool requireAuthentication,
@required bool longPressSelectionIsDefault,
@required AppLayout layout,
@required bool isTesting,
}) {
return _$UIState._(
selectedCompanyIndex: 0,
//layout: layout ?? AppLayout.mobile,
layout: layout ?? AppLayout.tablet,
historySidebarMode: (layout ?? AppLayout.tablet) == AppLayout.tablet
? AppSidebarMode.hide
: AppSidebarMode.float,
menuSidebarMode: AppSidebarMode.float,
isTesting: isTesting ?? false,
isMenuVisible: true,
isHistoryVisible: false,
@ -76,6 +81,10 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
AppLayout get layout;
AppSidebarMode get menuSidebarMode;
AppSidebarMode get historySidebarMode;
bool get isTesting;
bool get isMenuVisible;
@ -194,3 +203,18 @@ class AppSidebar extends EnumClass {
static AppSidebar valueOf(String name) => _$valueOfSidebar(name);
}
class AppSidebarMode extends EnumClass {
const AppSidebarMode._(String name) : super(name);
static Serializer<AppSidebarMode> get serializer =>
_$appSidebarModeSerializer;
static const AppSidebarMode float = _$float;
static const AppSidebarMode hide = _$hide;
static const AppSidebarMode collapse = _$collapse;
static BuiltSet<AppSidebarMode> get values => _$valuesSidebarMode;
static AppSidebarMode valueOf(String name) => _$valueOfSidebarMode(name);
}

View File

@ -49,9 +49,35 @@ final BuiltSet<AppSidebar> _$valuesSidebar =
_$history,
]);
const AppSidebarMode _$float = const AppSidebarMode._('float');
const AppSidebarMode _$hide = const AppSidebarMode._('hide');
const AppSidebarMode _$collapse = const AppSidebarMode._('collapse');
AppSidebarMode _$valueOfSidebarMode(String name) {
switch (name) {
case 'float':
return _$float;
case 'hide':
return _$hide;
case 'collapse':
return _$collapse;
default:
throw new ArgumentError(name);
}
}
final BuiltSet<AppSidebarMode> _$valuesSidebarMode =
new BuiltSet<AppSidebarMode>(const <AppSidebarMode>[
_$float,
_$hide,
_$collapse,
]);
Serializer<UIState> _$uIStateSerializer = new _$UIStateSerializer();
Serializer<AppLayout> _$appLayoutSerializer = new _$AppLayoutSerializer();
Serializer<AppSidebar> _$appSidebarSerializer = new _$AppSidebarSerializer();
Serializer<AppSidebarMode> _$appSidebarModeSerializer =
new _$AppSidebarModeSerializer();
class _$UIStateSerializer implements StructuredSerializer<UIState> {
@override
@ -66,6 +92,12 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
'layout',
serializers.serialize(object.layout,
specifiedType: const FullType(AppLayout)),
'menuSidebarMode',
serializers.serialize(object.menuSidebarMode,
specifiedType: const FullType(AppSidebarMode)),
'historySidebarMode',
serializers.serialize(object.historySidebarMode,
specifiedType: const FullType(AppSidebarMode)),
'isTesting',
serializers.serialize(object.isTesting,
specifiedType: const FullType(bool)),
@ -181,6 +213,14 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
result.layout = serializers.deserialize(value,
specifiedType: const FullType(AppLayout)) as AppLayout;
break;
case 'menuSidebarMode':
result.menuSidebarMode = serializers.deserialize(value,
specifiedType: const FullType(AppSidebarMode)) as AppSidebarMode;
break;
case 'historySidebarMode':
result.historySidebarMode = serializers.deserialize(value,
specifiedType: const FullType(AppSidebarMode)) as AppSidebarMode;
break;
case 'isTesting':
result.isTesting = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
@ -346,10 +386,32 @@ class _$AppSidebarSerializer implements PrimitiveSerializer<AppSidebar> {
AppSidebar.valueOf(serialized as String);
}
class _$AppSidebarModeSerializer
implements PrimitiveSerializer<AppSidebarMode> {
@override
final Iterable<Type> types = const <Type>[AppSidebarMode];
@override
final String wireName = 'AppSidebarMode';
@override
Object serialize(Serializers serializers, AppSidebarMode object,
{FullType specifiedType = FullType.unspecified}) =>
object.name;
@override
AppSidebarMode deserialize(Serializers serializers, Object serialized,
{FullType specifiedType = FullType.unspecified}) =>
AppSidebarMode.valueOf(serialized as String);
}
class _$UIState extends UIState {
@override
final AppLayout layout;
@override
final AppSidebarMode menuSidebarMode;
@override
final AppSidebarMode historySidebarMode;
@override
final bool isTesting;
@override
final bool isMenuVisible;
@ -415,6 +477,8 @@ class _$UIState extends UIState {
_$UIState._(
{this.layout,
this.menuSidebarMode,
this.historySidebarMode,
this.isTesting,
this.isMenuVisible,
this.isHistoryVisible,
@ -449,6 +513,12 @@ class _$UIState extends UIState {
if (layout == null) {
throw new BuiltValueNullFieldError('UIState', 'layout');
}
if (menuSidebarMode == null) {
throw new BuiltValueNullFieldError('UIState', 'menuSidebarMode');
}
if (historySidebarMode == null) {
throw new BuiltValueNullFieldError('UIState', 'historySidebarMode');
}
if (isTesting == null) {
throw new BuiltValueNullFieldError('UIState', 'isTesting');
}
@ -548,6 +618,8 @@ class _$UIState extends UIState {
if (identical(other, this)) return true;
return other is UIState &&
layout == other.layout &&
menuSidebarMode == other.menuSidebarMode &&
historySidebarMode == other.historySidebarMode &&
isTesting == other.isTesting &&
isMenuVisible == other.isMenuVisible &&
isHistoryVisible == other.isHistoryVisible &&
@ -600,7 +672,7 @@ class _$UIState extends UIState {
$jc(
$jc(
$jc(
$jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, layout.hashCode), isTesting.hashCode), isMenuVisible.hashCode), isHistoryVisible.hashCode), selectedCompanyIndex.hashCode), currentRoute.hashCode), previousRoute.hashCode), enableDarkMode.hashCode), accentColor.hashCode), longPressSelectionIsDefault.hashCode), requireAuthentication.hashCode), emailPayment.hashCode),
$jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, layout.hashCode), menuSidebarMode.hashCode), historySidebarMode.hashCode), isTesting.hashCode), isMenuVisible.hashCode), isHistoryVisible.hashCode), selectedCompanyIndex.hashCode), currentRoute.hashCode), previousRoute.hashCode), enableDarkMode.hashCode), accentColor.hashCode), longPressSelectionIsDefault.hashCode), requireAuthentication.hashCode), emailPayment.hashCode),
autoStartTasks.hashCode),
addDocumentsToInvoice.hashCode),
filter.hashCode),
@ -626,6 +698,8 @@ class _$UIState extends UIState {
String toString() {
return (newBuiltValueToStringHelper('UIState')
..add('layout', layout)
..add('menuSidebarMode', menuSidebarMode)
..add('historySidebarMode', historySidebarMode)
..add('isTesting', isTesting)
..add('isMenuVisible', isMenuVisible)
..add('isHistoryVisible', isHistoryVisible)
@ -667,6 +741,16 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
AppLayout get layout => _$this._layout;
set layout(AppLayout layout) => _$this._layout = layout;
AppSidebarMode _menuSidebarMode;
AppSidebarMode get menuSidebarMode => _$this._menuSidebarMode;
set menuSidebarMode(AppSidebarMode menuSidebarMode) =>
_$this._menuSidebarMode = menuSidebarMode;
AppSidebarMode _historySidebarMode;
AppSidebarMode get historySidebarMode => _$this._historySidebarMode;
set historySidebarMode(AppSidebarMode historySidebarMode) =>
_$this._historySidebarMode = historySidebarMode;
bool _isTesting;
bool get isTesting => _$this._isTesting;
set isTesting(bool isTesting) => _$this._isTesting = isTesting;
@ -834,6 +918,8 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
UIStateBuilder get _$this {
if (_$v != null) {
_layout = _$v.layout;
_menuSidebarMode = _$v.menuSidebarMode;
_historySidebarMode = _$v.historySidebarMode;
_isTesting = _$v.isTesting;
_isMenuVisible = _$v.isMenuVisible;
_isHistoryVisible = _$v.isHistoryVisible;
@ -889,6 +975,8 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
_$result = _$v ??
new _$UIState._(
layout: layout,
menuSidebarMode: menuSidebarMode,
historySidebarMode: historySidebarMode,
isTesting: isTesting,
isMenuVisible: isMenuVisible,
isHistoryVisible: isHistoryVisible,

View File

@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/history_drawer_vm.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class HistoryDrawer extends StatelessWidget {
const HistoryDrawer({
@ -12,14 +13,12 @@ class HistoryDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
return Drawer(
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('History')
],
child: Scaffold(
appBar: AppBar(
title: Text(localization.history),
),
),
);

View File

@ -30,7 +30,8 @@ class _DeviceSettingsState extends State<DeviceSettings> {
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
final viewModel = widget.viewModel;
final uiState = viewModel.state.uiState;
final state = viewModel.state;
final uiState = state.uiState;
return WillPopScope(
onWillPop: () async {
@ -65,6 +66,44 @@ class _DeviceSettingsState extends State<DeviceSettings> {
),
],
),
AppDropdownButton<AppSidebarMode>(
labelText: localization.menuSidebar,
value: state.uiState.menuSidebarMode,
items: [
DropdownMenuItem(
child: Text(localization.showOrHide),
value: AppSidebarMode.hide,
),
DropdownMenuItem(
child: Text(localization.float),
value: AppSidebarMode.float,
),
/* TODO implement
DropdownMenuItem(
child: Text(localization.collapse),
value: AppSidebarMode.collapse,
),
*/
],
onChanged: (dynamic value) =>
viewModel.onMenuModeChanged(context, value),
),
AppDropdownButton<AppSidebarMode>(
labelText: localization.historySidebar,
value: state.uiState.historySidebarMode,
items: [
DropdownMenuItem(
child: Text(localization.showOrHide),
value: AppSidebarMode.hide,
),
DropdownMenuItem(
child: Text(localization.float),
value: AppSidebarMode.float,
),
],
onChanged: (dynamic value) =>
viewModel.onHistoryModeChanged(context, value),
),
FormColorPicker(
labelText: localization.accentColor,
initialValue: uiState.accentColor,

View File

@ -45,6 +45,8 @@ class DeviceSettingsVM {
@required this.onAccentColorChanged,
@required this.onLongPressSelectionIsDefault,
@required this.authenticationSupported,
@required this.onMenuModeChanged,
@required this.onHistoryModeChanged,
});
static DeviceSettingsVM fromStore(Store<AppState> store) {
@ -121,12 +123,30 @@ class DeviceSettingsVM {
onLongPressSelectionIsDefault: (BuildContext context, bool value) async {
if (!kIsWeb) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool(kSharedPrefLongPressSelectionIsDefault, value);
prefs.setBool(kSharedPrefLongPressSelection, value);
}
store.dispatch(UserSettingsChanged(longPressSelectionIsDefault: value));
AppBuilder.of(context).rebuild();
},
onLayoutChanged: (BuildContext context, AppLayout value) {
onMenuModeChanged: (context, value) async {
if (!kIsWeb) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(kSharedPrefMenuMode, '$value');
}
store.dispatch(UserSettingsChanged(menuMode: value));
},
onHistoryModeChanged: (context, value) async {
if (!kIsWeb) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(kSharedPrefHistoryMode, '$value');
}
store.dispatch(UserSettingsChanged(historyMode: value));
},
onLayoutChanged: (BuildContext context, AppLayout value) async {
if (!kIsWeb) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(kSharedPrefLayout, '$value');
}
store.dispatch(UpdateLayout(value));
AppBuilder.of(context).rebuild();
if (value == AppLayout.mobile) {
@ -134,7 +154,6 @@ class DeviceSettingsVM {
} else {
store.dispatch(ViewMainScreen(context));
}
},
onRequireAuthenticationChanged: (BuildContext context, bool value) async {
bool authenticated = false;
@ -174,6 +193,8 @@ class DeviceSettingsVM {
final Function(BuildContext) onRefreshTap;
final Function(BuildContext, bool) onDarkModeChanged;
final Function(BuildContext, AppLayout) onLayoutChanged;
final Function(BuildContext, AppSidebarMode) onMenuModeChanged;
final Function(BuildContext, AppSidebarMode) onHistoryModeChanged;
final Function(BuildContext, String) onAccentColorChanged;
final Function(BuildContext, bool) onAutoStartTasksChanged;
final Function(BuildContext, bool) onLongPressSelectionIsDefault;

View File

@ -14,6 +14,11 @@ abstract class LocaleCodeAware {
mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
'float': 'Float',
'collapse': 'Collapse',
'show_or_hide': 'Show/hide',
'menu_sidebar': 'Menu Sidebar',
'history_sidebar': 'History Sidebar',
'tablet': 'Tablet',
'mobile': 'Mobile',
'desktop': 'Desktop',
@ -15742,6 +15747,16 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get tablet => _localizedValues[localeCode]['tablet'];
String get float => _localizedValues[localeCode]['float'];
String get collapse => _localizedValues[localeCode]['collapse'];
String get showOrHide => _localizedValues[localeCode]['show_or_hide'];
String get menuSidebar => _localizedValues[localeCode]['menu_sidebar'];
String get historySidebar => _localizedValues[localeCode]['history_sidebar'];
String lookup(String key) {
final lookupKey = toSnakeCase(key);
return _localizedValues[localeCode][lookupKey] ??