This commit is contained in:
Hillel Coren 2019-08-21 12:44:06 +03:00
parent 8fac0d9d90
commit 435a532960
11 changed files with 92 additions and 30 deletions

View File

@ -109,7 +109,7 @@ class WebClient {
.timeout(const Duration(seconds: 30)); .timeout(const Duration(seconds: 30));
} }
print('response: ${response.body}'); //print('response: ${response.body}');
if (response.statusCode >= 300) { if (response.statusCode >= 300) {
print('==== FAILED ===='); print('==== FAILED ====');
@ -170,7 +170,7 @@ class WebClient {
}, },
); );
print('response: ${response.body}'); //print('response: ${response.body}');
if (response.statusCode >= 300) { if (response.statusCode >= 300) {
print('==== FAILED ===='); print('==== FAILED ====');

View File

@ -48,7 +48,8 @@ import 'package:invoiceninja_flutter/redux/quote/quote_actions.dart';
import 'package:invoiceninja_flutter/redux/quote/quote_middleware.dart'; import 'package:invoiceninja_flutter/redux/quote/quote_middleware.dart';
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
void main() async { void main({bool isTesting = false}) async {
final SentryClient _sentry = Config.SENTRY_DNS.isEmpty final SentryClient _sentry = Config.SENTRY_DNS.isEmpty
? null ? null
: SentryClient( : SentryClient(
@ -68,6 +69,7 @@ void main() async {
enableDarkMode: enableDarkMode, enableDarkMode: enableDarkMode,
requireAuthentication: requireAuthentication, requireAuthentication: requireAuthentication,
layout: AppLayout.tablet, layout: AppLayout.tablet,
isTesting: isTesting,
), ),
middleware: [] middleware: []
..addAll(createStoreAuthMiddleware()) ..addAll(createStoreAuthMiddleware())
@ -86,7 +88,9 @@ void main() async {
..addAll(createStoreSettingsMiddleware()) ..addAll(createStoreSettingsMiddleware())
// STARTER: middleware - do not remove comment // STARTER: middleware - do not remove comment
..addAll([ ..addAll([
LoggingMiddleware<dynamic>.printer(), LoggingMiddleware<dynamic>.printer(
formatter: LoggingMiddleware.multiLineFormatter,
),
])); ]));
Future<void> _reportError(dynamic error, dynamic stackTrace) async { Future<void> _reportError(dynamic error, dynamic stackTrace) async {

View File

@ -13,7 +13,8 @@ AppState appReducer(AppState state, dynamic action) {
if (action is UserLogout) { if (action is UserLogout) {
return AppState().rebuild((b) => b return AppState().rebuild((b) => b
..authState.replace(state.authState) ..authState.replace(state.authState)
..uiState.enableDarkMode = state.uiState.enableDarkMode); ..uiState.enableDarkMode = state.uiState.enableDarkMode
..uiState.isTesting = state.uiState.isTesting);
} else if (action is LoadStateSuccess) { } else if (action is LoadStateSuccess) {
return action.state.rebuild((b) => b return action.state.rebuild((b) => b
..isLoading = false ..isLoading = false

View File

@ -41,6 +41,7 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
bool enableDarkMode, bool enableDarkMode,
bool requireAuthentication, bool requireAuthentication,
AppLayout layout, AppLayout layout,
bool isTesting,
}) { }) {
return _$AppState._( return _$AppState._(
isLoading: false, isLoading: false,
@ -58,6 +59,7 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
enableDarkMode: enableDarkMode, enableDarkMode: enableDarkMode,
requireAuthentication: requireAuthentication, requireAuthentication: requireAuthentication,
layout: layout ?? AppLayout.mobile, layout: layout ?? AppLayout.mobile,
isTesting: isTesting,
), ),
); );
} }
@ -264,6 +266,7 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
@override @override
String toString() { String toString() {
return 'Route: ${uiState.currentRoute}, Previous: ${uiState.previousRoute}, Layout: ${uiState.layout}, Menu: ${uiState.isMenuVisible}, History: ${uiState.isHistoryVisible}'; return 'Is Testing: ${uiState.isTesting}';
//return 'Route: ${uiState.currentRoute}, Previous: ${uiState.previousRoute}, Layout: ${uiState.layout}, Menu: ${uiState.isMenuVisible}, History: ${uiState.isHistoryVisible}';
} }
} }

View File

@ -26,12 +26,18 @@ import 'package:invoiceninja_flutter/redux/quote/quote_state.dart';
part 'ui_state.g.dart'; part 'ui_state.g.dart';
abstract class UIState implements Built<UIState, UIStateBuilder> { abstract class UIState implements Built<UIState, UIStateBuilder> {
factory UIState(CompanyEntity company, factory UIState(
{bool enableDarkMode, bool requireAuthentication, AppLayout layout}) { CompanyEntity company, {
bool enableDarkMode,
bool requireAuthentication,
AppLayout layout,
bool isTesting,
}) {
return _$UIState._( return _$UIState._(
selectedCompanyIndex: 0, selectedCompanyIndex: 0,
//layout: layout ?? AppLayout.mobile, //layout: layout ?? AppLayout.mobile,
layout: layout ?? AppLayout.tablet, layout: layout ?? AppLayout.tablet,
isTesting: isTesting ?? false,
isMenuVisible: true, isMenuVisible: true,
isHistoryVisible: false, isHistoryVisible: false,
currentRoute: LoginScreen.route, currentRoute: LoginScreen.route,
@ -60,6 +66,8 @@ abstract class UIState implements Built<UIState, UIStateBuilder> {
AppLayout get layout; AppLayout get layout;
bool get isTesting;
bool get isMenuVisible; bool get isMenuVisible;
bool get isHistoryVisible; bool get isHistoryVisible;

View File

@ -66,6 +66,9 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
'layout', 'layout',
serializers.serialize(object.layout, serializers.serialize(object.layout,
specifiedType: const FullType(AppLayout)), specifiedType: const FullType(AppLayout)),
'isTesting',
serializers.serialize(object.isTesting,
specifiedType: const FullType(bool)),
'isMenuVisible', 'isMenuVisible',
serializers.serialize(object.isMenuVisible, serializers.serialize(object.isMenuVisible,
specifiedType: const FullType(bool)), specifiedType: const FullType(bool)),
@ -154,6 +157,10 @@ class _$UIStateSerializer implements StructuredSerializer<UIState> {
result.layout = serializers.deserialize(value, result.layout = serializers.deserialize(value,
specifiedType: const FullType(AppLayout)) as AppLayout; specifiedType: const FullType(AppLayout)) as AppLayout;
break; break;
case 'isTesting':
result.isTesting = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
break;
case 'isMenuVisible': case 'isMenuVisible':
result.isMenuVisible = serializers.deserialize(value, result.isMenuVisible = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool; specifiedType: const FullType(bool)) as bool;
@ -289,6 +296,8 @@ class _$UIState extends UIState {
@override @override
final AppLayout layout; final AppLayout layout;
@override @override
final bool isTesting;
@override
final bool isMenuVisible; final bool isMenuVisible;
@override @override
final bool isHistoryVisible; final bool isHistoryVisible;
@ -338,6 +347,7 @@ class _$UIState extends UIState {
_$UIState._( _$UIState._(
{this.layout, {this.layout,
this.isTesting,
this.isMenuVisible, this.isMenuVisible,
this.isHistoryVisible, this.isHistoryVisible,
this.selectedCompanyIndex, this.selectedCompanyIndex,
@ -364,6 +374,9 @@ class _$UIState extends UIState {
if (layout == null) { if (layout == null) {
throw new BuiltValueNullFieldError('UIState', 'layout'); throw new BuiltValueNullFieldError('UIState', 'layout');
} }
if (isTesting == null) {
throw new BuiltValueNullFieldError('UIState', 'isTesting');
}
if (isMenuVisible == null) { if (isMenuVisible == null) {
throw new BuiltValueNullFieldError('UIState', 'isMenuVisible'); throw new BuiltValueNullFieldError('UIState', 'isMenuVisible');
} }
@ -441,6 +454,7 @@ class _$UIState extends UIState {
if (identical(other, this)) return true; if (identical(other, this)) return true;
return other is UIState && return other is UIState &&
layout == other.layout && layout == other.layout &&
isTesting == other.isTesting &&
isMenuVisible == other.isMenuVisible && isMenuVisible == other.isMenuVisible &&
isHistoryVisible == other.isHistoryVisible && isHistoryVisible == other.isHistoryVisible &&
selectedCompanyIndex == other.selectedCompanyIndex && selectedCompanyIndex == other.selectedCompanyIndex &&
@ -485,7 +499,7 @@ class _$UIState extends UIState {
$jc( $jc(
$jc( $jc(
$jc( $jc(
$jc($jc($jc($jc($jc(0, layout.hashCode), isMenuVisible.hashCode), isHistoryVisible.hashCode), selectedCompanyIndex.hashCode), $jc($jc($jc($jc($jc($jc(0, layout.hashCode), isTesting.hashCode), isMenuVisible.hashCode), isHistoryVisible.hashCode), selectedCompanyIndex.hashCode),
currentRoute.hashCode), currentRoute.hashCode),
previousRoute.hashCode), previousRoute.hashCode),
enableDarkMode.hashCode), enableDarkMode.hashCode),
@ -511,6 +525,7 @@ class _$UIState extends UIState {
String toString() { String toString() {
return (newBuiltValueToStringHelper('UIState') return (newBuiltValueToStringHelper('UIState')
..add('layout', layout) ..add('layout', layout)
..add('isTesting', isTesting)
..add('isMenuVisible', isMenuVisible) ..add('isMenuVisible', isMenuVisible)
..add('isHistoryVisible', isHistoryVisible) ..add('isHistoryVisible', isHistoryVisible)
..add('selectedCompanyIndex', selectedCompanyIndex) ..add('selectedCompanyIndex', selectedCompanyIndex)
@ -544,6 +559,10 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
AppLayout get layout => _$this._layout; AppLayout get layout => _$this._layout;
set layout(AppLayout layout) => _$this._layout = layout; set layout(AppLayout layout) => _$this._layout = layout;
bool _isTesting;
bool get isTesting => _$this._isTesting;
set isTesting(bool isTesting) => _$this._isTesting = isTesting;
bool _isMenuVisible; bool _isMenuVisible;
bool get isMenuVisible => _$this._isMenuVisible; bool get isMenuVisible => _$this._isMenuVisible;
set isMenuVisible(bool isMenuVisible) => set isMenuVisible(bool isMenuVisible) =>
@ -667,6 +686,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
UIStateBuilder get _$this { UIStateBuilder get _$this {
if (_$v != null) { if (_$v != null) {
_layout = _$v.layout; _layout = _$v.layout;
_isTesting = _$v.isTesting;
_isMenuVisible = _$v.isMenuVisible; _isMenuVisible = _$v.isMenuVisible;
_isHistoryVisible = _$v.isHistoryVisible; _isHistoryVisible = _$v.isHistoryVisible;
_selectedCompanyIndex = _$v.selectedCompanyIndex; _selectedCompanyIndex = _$v.selectedCompanyIndex;
@ -714,6 +734,7 @@ class UIStateBuilder implements Builder<UIState, UIStateBuilder> {
_$result = _$v ?? _$result = _$v ??
new _$UIState._( new _$UIState._(
layout: layout, layout: layout,
isTesting: isTesting,
isMenuVisible: isMenuVisible, isMenuVisible: isMenuVisible,
isHistoryVisible: isHistoryVisible, isHistoryVisible: isHistoryVisible,
selectedCompanyIndex: selectedCompanyIndex, selectedCompanyIndex: selectedCompanyIndex,

View File

@ -1,5 +1,6 @@
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/resources/cached_image.dart';
import 'package:redux/redux.dart'; import 'package:redux/redux.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';
@ -17,7 +18,6 @@ import 'package:invoiceninja_flutter/utils/keys.dart';
import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_actions.dart'; import 'package:invoiceninja_flutter/redux/expense/expense_actions.dart';
import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart'; import 'package:invoiceninja_flutter/redux/vendor/vendor_actions.dart';
import 'package:invoiceninja_flutter/redux/task/task_actions.dart'; import 'package:invoiceninja_flutter/redux/task/task_actions.dart';
@ -60,16 +60,10 @@ class AppDrawer extends StatelessWidget {
height: 30, height: 30,
) )
: company.logoUrl != null && company.logoUrl.isNotEmpty : company.logoUrl != null && company.logoUrl.isNotEmpty
? CachedNetworkImage( ? CachedImage(
width: 32, width: 32,
height: 30, height: 30,
key: ValueKey(company.logoUrl), url: company.logoUrl,
imageUrl: company.logoUrl,
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Image.asset(
'assets/images/logo.png',
width: 32,
height: 30),
) )
: Image.asset('assets/images/logo.png', width: 32, height: 30), : Image.asset('assets/images/logo.png', width: 32, height: 30),
SizedBox(width: 28, height: 50), SizedBox(width: 28, height: 50),
@ -104,17 +98,10 @@ class AppDrawer extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[ children: <Widget>[
company.logoUrl != null && company.logoUrl.isNotEmpty company.logoUrl != null && company.logoUrl.isNotEmpty
? CachedNetworkImage( ? CachedImage(
width: 32, width: 32,
height: 30, height: 30,
key: ValueKey(company.logoUrl), url: company.logoUrl,
imageUrl: company.logoUrl,
placeholder: (context, url) =>
CircularProgressIndicator(),
errorWidget: (context, url, error) => Image.asset(
'assets/images/logo.png',
width: 32,
height: 30),
) )
: Image.asset('assets/images/logo.png', : Image.asset('assets/images/logo.png',
width: 32, height: 30), width: 32, height: 30),

View File

@ -0,0 +1,39 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class CachedImage extends StatelessWidget {
const CachedImage({this.url, this.width, this.height, this.showNinjaOnError = true});
final String url;
final bool showNinjaOnError;
final double width;
final double height;
@override
Widget build(BuildContext context) {
final store = StoreProvider.of<AppState>(context);
final uiState = store.state.uiState;
// TODO remove this workaround
if (uiState.isTesting) {
return SizedBox(
width: width,
height: height,
);
}
return CachedNetworkImage(
width: 32,
height: 30,
key: ValueKey(url),
imageUrl: url,
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Image.asset(
'assets/images/logo.png',
width: 32,
height: 30),
);
}
}

View File

@ -1,7 +1,6 @@
class AppKeys { class AppKeys {
static const String openAppDrawer = 'Open navigation menu'; static const String openAppDrawer = 'Open navigation menu';
static const String dashboardScreen = 'DashboardScreen'; static const String dashboardScreen = 'DashboardScreen';
static const String successfullyCreated = 'Successfully created';
} }
class AppTooltips { class AppTooltips {

View File

@ -6,5 +6,5 @@ import 'package:invoiceninja_flutter/main.dart' as app;
void main() { void main() {
// This line enables the extension // This line enables the extension
enableFlutterDriverExtension(); enableFlutterDriverExtension();
app.main(); app.main(isTesting: true);
} }

View File

@ -31,7 +31,7 @@ Future<void> login(FlutterDriver driver,
Future<void> logout(FlutterDriver driver, TestLocalization localization) async { Future<void> logout(FlutterDriver driver, TestLocalization localization) async {
// Go to Settings Screen // Go to Settings Screen
await driver.tap(find.byTooltip(AppKeys.openAppDrawer)); await driver.tap(find.byTooltip(AppKeys.openAppDrawer));
await driver.scrollUntilVisible(find.byType('Drawer'), find.byValueKey(SettingsKeys.drawer)); //await driver.scrollUntilVisible(find.byType('Drawer'), find.byValueKey(SettingsKeys.drawer));
await driver.tap(find.byValueKey(SettingsKeys.drawer)); await driver.tap(find.byValueKey(SettingsKeys.drawer));
// Tap on Log Out // Tap on Log Out