This commit is contained in:
Hillel Coren 2020-02-16 16:33:05 +02:00
parent c657e0d8a2
commit 22a474aae5
5 changed files with 169 additions and 105 deletions

View File

@ -86,6 +86,7 @@ class ReportsScreen extends StatelessWidget {
Builder(builder: (BuildContext context) {
return FlatButton(
child: Text(localization.columns),
textColor: Colors.white,
onPressed: () {
multiselectDialog(
context: context,
@ -100,6 +101,13 @@ class ReportsScreen extends StatelessWidget {
},
);
}),
FlatButton(
child: Text(localization.export),
textColor: Colors.white,
onPressed: () {
viewModel.onExportPressed(context);
},
)
],
),
body: ListView(
@ -580,12 +588,27 @@ class ReportResult {
return true;
}
List<String> sortedColumns(BuildContext context) {
final store = StoreProvider.of<AppState>(context);
final group = store.state.uiState.reportsUIState.group;
final data = columns.toList();
/*
if (group.isNotEmpty) {
data.remove(group);
data.insert(0, group);
}
*/
return data;
}
List<DataColumn> tableColumns(
BuildContext context, Function(int, bool) onSortCallback) {
final localization = AppLocalization.of(context);
return [
for (String column in columns)
for (String column in sortedColumns(context))
DataColumn(
tooltip: localization.lookup(column),
label: Container(
@ -607,7 +630,7 @@ class ReportResult {
Function(String, String) onFilterChanged) {
final localization = AppLocalization.of(context);
return DataRow(cells: [
for (String column in columns)
for (String column in sortedColumns(context))
if (getReportColumnType(column) == ReportColumnType.bool)
DataCell(AppDropdownButton<bool>(
labelText: null,
@ -743,7 +766,7 @@ class ReportResult {
} else {
viewModel.reportTotals.forEach((group, values) {
final cells = <DataCell>[];
for (var column in columns) {
for (var column in sortedColumns(context)) {
String value = '';
if (column == groupBy) {
if (getReportColumnType(column) == ReportColumnType.dateTime) {

View File

@ -1,3 +1,6 @@
import 'dart:html';
import 'dart:io' as file;
import 'package:flutter_share/flutter_share.dart';
import 'package:built_collection/built_collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -16,6 +19,7 @@ import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:memoize/memoize.dart';
import 'package:path_provider/path_provider.dart';
import 'package:redux/redux.dart';
import 'reports_screen.dart';
@ -42,6 +46,7 @@ class ReportsScreenVM {
@required this.onSettingsChanged,
@required this.onReportColumnsChanged,
@required this.onReportFiltersChanged,
@required this.onExportPressed,
@required this.onReportSorted,
@required this.reportTotals,
@required this.reportResult,
@ -51,6 +56,7 @@ class ReportsScreenVM {
final ReportResult reportResult;
final Map<String, Map<String, double>> reportTotals;
final Function(BuildContext, List<String>) onReportColumnsChanged;
final Function(BuildContext) onExportPressed;
final Function(BuildContext, BuiltMap<String, String>) onReportFiltersChanged;
final Function(int, bool) onReportSorted;
final Function({
@ -79,91 +85,114 @@ class ReportsScreenVM {
break;
}
print('## TOTALS: ${memoizedReportTotals(reportResult, state.uiState.reportsUIState)}');
print(
'## TOTALS: ${memoizedReportTotals(reportResult, state.uiState.reportsUIState)}');
return ReportsScreenVM(
state: state,
reportResult: reportResult,
reportTotals:
memoizedReportTotals(reportResult, state.uiState.reportsUIState),
onReportSorted: (index, ascending) {
store.dispatch(UpdateReportSettings(
report: state.uiState.reportsUIState.report,
sortIndex: index,
));
},
onReportFiltersChanged: (context, filterMap) {
store.dispatch(UpdateReportSettings(
report: report,
filters: filterMap,
));
},
onReportColumnsChanged: (context, columns) {
final allReportSettings = state.userCompany.settings.reportSettings;
final reportSettings =
(allReportSettings != null && allReportSettings.containsKey(report)
? allReportSettings[report]
: ReportSettingsEntity())
.rebuild((b) => b..columns.replace(BuiltList<String>(columns)));
final user = state.user.rebuild((b) => b
..userCompany
.settings
.reportSettings[state.uiState.reportsUIState.report] =
reportSettings);
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).savedSettings);
if (state.authState.hasRecentlyEnteredPassword) {
store.dispatch(
SaveUserSettingsRequest(
completer: completer,
user: user,
),
);
} else {
passwordCallback(
context: context,
callback: (password) {
store.dispatch(
SaveUserSettingsRequest(
completer: completer,
user: user,
password: password,
),
);
});
}
},
onSettingsChanged: ({
String report,
String group,
String subgroup,
String chart,
String customStartDate,
String customEndDate,
}) {
final reportState = state.uiState.reportsUIState;
if (group != null && reportState.group != group) {
state: state,
reportResult: reportResult,
reportTotals:
memoizedReportTotals(reportResult, state.uiState.reportsUIState),
onReportSorted: (index, ascending) {
store.dispatch(UpdateReportSettings(
report: report ?? reportState.report,
group: group,
chart: chart,
subgroup: subgroup,
customStartDate: '',
customEndDate: '',
filters: BuiltMap<String, String>(),
report: state.uiState.reportsUIState.report,
sortIndex: index,
));
} else {
},
onReportFiltersChanged: (context, filterMap) {
store.dispatch(UpdateReportSettings(
report: report ?? reportState.report,
group: group,
subgroup: subgroup,
chart: chart,
customStartDate: customStartDate,
customEndDate: customEndDate,
report: report,
filters: filterMap,
));
}
},
);
},
onReportColumnsChanged: (context, columns) {
final allReportSettings = state.userCompany.settings.reportSettings;
final reportSettings = (allReportSettings != null &&
allReportSettings.containsKey(report)
? allReportSettings[report]
: ReportSettingsEntity())
.rebuild((b) => b..columns.replace(BuiltList<String>(columns)));
final user = state.user.rebuild((b) => b
..userCompany
.settings
.reportSettings[state.uiState.reportsUIState.report] =
reportSettings);
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).savedSettings);
if (state.authState.hasRecentlyEnteredPassword) {
store.dispatch(
SaveUserSettingsRequest(
completer: completer,
user: user,
),
);
} else {
passwordCallback(
context: context,
callback: (password) {
store.dispatch(
SaveUserSettingsRequest(
completer: completer,
user: user,
password: password,
),
);
});
}
},
onSettingsChanged: ({
String report,
String group,
String subgroup,
String chart,
String customStartDate,
String customEndDate,
}) {
final reportState = state.uiState.reportsUIState;
if (group != null && reportState.group != group) {
store.dispatch(UpdateReportSettings(
report: report ?? reportState.report,
group: group,
chart: chart,
subgroup: subgroup,
customStartDate: '',
customEndDate: '',
filters: BuiltMap<String, String>(),
));
} else {
store.dispatch(UpdateReportSettings(
report: report ?? reportState.report,
group: group,
subgroup: subgroup,
chart: chart,
customStartDate: customStartDate,
customEndDate: customEndDate,
));
}
},
onExportPressed: (context) async {
print('## EXPORT ##');
String data = 'test_data';
const filename = 'export.csv';
if (kIsWeb) {
final encodedFileContents = Uri.encodeComponent(data);
AnchorElement(
href: 'data:text/plain;charset=utf-8,$encodedFileContents')
..setAttribute('download', filename)
..click();
} else {
final directory = await getApplicationDocumentsDirectory();
final filePath = '$directory/$filename';
final csvFile = file.File(filePath);
csvFile.writeAsString(data);
await FlutterShare.shareFile(
title: 'Example share',
text: 'Example share text',
filePath: filePath);
}
});
}
}

View File

@ -14,6 +14,7 @@ abstract class LocaleCodeAware {
mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
'export': 'Export',
'chart': 'Chart',
'count': 'Count',
'totals': 'Totals',
@ -16097,6 +16098,9 @@ mixin LocalizationsProvider on LocaleCodeAware {
String get chart => _localizedValues[localeCode]['chart'];
String get export => _localizedValues[localeCode]['export'];
String lookup(String key) {
final lookupKey = toSnakeCase(key);
return _localizedValues[localeCode][lookupKey] ??

View File

@ -56,7 +56,7 @@ packages:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.1+1"
version: "0.4.2"
build_daemon:
dependency: transitive
description:
@ -77,14 +77,14 @@ packages:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.3"
version: "1.7.4"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.0"
version: "4.4.0"
built_collection:
dependency: "direct main"
description:
@ -168,7 +168,7 @@ packages:
name: coverage
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.3+3"
version: "0.13.6"
crypto:
dependency: transitive
description:
@ -196,7 +196,7 @@ packages:
name: extended_image
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.8"
version: "0.6.9"
extended_image_library:
dependency: transitive
description:
@ -217,7 +217,7 @@ packages:
name: faker
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.2.1"
file:
dependency: transitive
description:
@ -231,7 +231,7 @@ packages:
name: firebase
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.0"
version: "7.2.1"
firebase_auth:
dependency: "direct main"
description:
@ -245,7 +245,7 @@ packages:
name: firebase_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3+2"
version: "0.4.4"
firebase_core_platform_interface:
dependency: transitive
description:
@ -316,7 +316,7 @@ packages:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "1.0.5"
flutter_redux:
dependency: "direct main"
description:
@ -324,6 +324,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.4"
flutter_share:
dependency: "direct main"
description:
name: flutter_share
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2+1"
flutter_slidable:
dependency: "direct main"
description:
@ -342,7 +349,7 @@ packages:
name: flutter_typeahead
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "1.8.0"
flutter_web_plugins:
dependency: transitive
description: flutter
@ -394,7 +401,7 @@ packages:
name: google_sign_in_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.3"
version: "0.8.3+1"
graphs:
dependency: transitive
description:
@ -429,7 +436,7 @@ packages:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.0"
http_parser:
dependency: transitive
description:
@ -618,7 +625,7 @@ packages:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.1"
version: "1.6.0"
pedantic:
dependency: transitive
description:
@ -681,7 +688,7 @@ packages:
name: quill_delta
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.0.1"
quiver:
dependency: transitive
description:
@ -730,14 +737,14 @@ packages:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.6"
version: "0.5.6+1"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+3"
version: "0.0.1+5"
shared_preferences_platform_interface:
dependency: transitive
description:
@ -751,7 +758,7 @@ packages:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2+2"
version: "0.1.2+3"
shelf:
dependency: transitive
description:
@ -805,7 +812,7 @@ packages:
name: source_maps
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.8"
version: "0.10.9"
source_span:
dependency: transitive
description:
@ -861,7 +868,7 @@ packages:
name: synchronized
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.2.0"
term_glyph:
dependency: transitive
description:
@ -896,7 +903,7 @@ packages:
name: timeago
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.24"
version: "2.0.26"
timing:
dependency: transitive
description:
@ -938,7 +945,7 @@ packages:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0+2"
version: "0.1.1"
usage:
dependency: transitive
description:
@ -1001,7 +1008,7 @@ packages:
name: webview_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.19+5"
version: "0.3.19+7"
xml:
dependency: transitive
description:

View File

@ -36,7 +36,7 @@ dependencies:
sentry: ^2.2.0
image_picker: ^0.6.1+4
zefyr: ^0.8.0
flutter_colorpicker: any
flutter_colorpicker: ^0.2.0
flutter_json_widget: ^1.0.2
webview_flutter: ^0.3.15+1
timeago: ^2.0.22
@ -44,6 +44,7 @@ dependencies:
native_pdf_view: any
flutter_typeahead: ^1.7.0
#quick_actions: ^0.2.1
flutter_share: ^1.0.2+1
dev_dependencies:
flutter_driver: