381 lines
12 KiB
Dart
381 lines
12 KiB
Dart
|
|
import 'dart:async';
|
||
|
|
import 'dart:io';
|
||
|
|
|
||
|
|
import 'package:downloads_path_provider/downloads_path_provider.dart';
|
||
|
|
import 'package:flutter/cupertino.dart';
|
||
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:flutter_downloader/flutter_downloader.dart';
|
||
|
|
import 'package:intl/intl.dart';
|
||
|
|
import 'package:open_file/open_file.dart';
|
||
|
|
import 'package:path_provider/path_provider.dart';
|
||
|
|
import 'package:permission_handler/permission_handler.dart';
|
||
|
|
import 'package:provider/provider.dart';
|
||
|
|
import 'package:fcs/model/language_model.dart';
|
||
|
|
import 'package:fcs/model/report_model.dart';
|
||
|
|
import 'package:fcs/pages/util.dart';
|
||
|
|
import 'package:fcs/theme/theme.dart';
|
||
|
|
import 'package:fcs/vo/report.dart';
|
||
|
|
import 'package:fcs/widget/my_data_table.dart';
|
||
|
|
import 'package:fcs/widget/progress.dart';
|
||
|
|
|
||
|
|
import 'report_field_list_page.dart';
|
||
|
|
import 'report_filter_list_page.dart';
|
||
|
|
|
||
|
|
class ReportsDataTable extends StatefulWidget {
|
||
|
|
final Report report;
|
||
|
|
ReportsDataTable({this.report});
|
||
|
|
@override
|
||
|
|
_ReportsDataTableState createState() => _ReportsDataTableState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _ReportsDataTableState extends State<ReportsDataTable> {
|
||
|
|
Report report;
|
||
|
|
int limit = 20;
|
||
|
|
int offset = 0;
|
||
|
|
final numberFormatter = new NumberFormat("#,###");
|
||
|
|
var dateFormatter = new DateFormat('dd MMM yyyy\nhh:mm:ss a');
|
||
|
|
|
||
|
|
List _initialDisplayFields = [];
|
||
|
|
List<Field> _initialFields = [];
|
||
|
|
List _initialfieldList = [];
|
||
|
|
|
||
|
|
List<Field> displayFields = [];
|
||
|
|
List dataList = [];
|
||
|
|
List cellfields = [];
|
||
|
|
List fieldList = [];
|
||
|
|
bool sort;
|
||
|
|
bool _isLoading;
|
||
|
|
int sortColumnIndex = 1;
|
||
|
|
bool _endOfData;
|
||
|
|
TargetPlatform platform;
|
||
|
|
bool _permissionReady;
|
||
|
|
String _localPath;
|
||
|
|
|
||
|
|
@override
|
||
|
|
void initState() {
|
||
|
|
_controller = ScrollController();
|
||
|
|
_controller.addListener(_scrollListener);
|
||
|
|
|
||
|
|
super.initState();
|
||
|
|
sort = false;
|
||
|
|
_isLoading = true;
|
||
|
|
_endOfData = false;
|
||
|
|
_permissionReady = false;
|
||
|
|
_load();
|
||
|
|
}
|
||
|
|
|
||
|
|
_prepare() async {
|
||
|
|
platform = Theme.of(context).platform;
|
||
|
|
|
||
|
|
_permissionReady = await _checkPermission();
|
||
|
|
|
||
|
|
_localPath = (await _findLocalPath()) + Platform.pathSeparator + 'Download';
|
||
|
|
|
||
|
|
final savedDir = Directory(_localPath);
|
||
|
|
bool hasExisted = await savedDir.exists();
|
||
|
|
if (!hasExisted) {
|
||
|
|
savedDir.create();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<bool> _checkPermission() async {
|
||
|
|
if (platform == TargetPlatform.android) {
|
||
|
|
PermissionStatus permission = await PermissionHandler()
|
||
|
|
.checkPermissionStatus(PermissionGroup.storage);
|
||
|
|
if (permission != PermissionStatus.granted) {
|
||
|
|
Map<PermissionGroup, PermissionStatus> permissions =
|
||
|
|
await PermissionHandler()
|
||
|
|
.requestPermissions([PermissionGroup.storage]);
|
||
|
|
if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
_load() async {
|
||
|
|
var reportModel = Provider.of<ReportModel>(context, listen: false);
|
||
|
|
var data = await reportModel.getReport(widget.report.id);
|
||
|
|
reportModel.getReport(widget.report.id).then((_report) {
|
||
|
|
// var data = await reportModel.loadSelectedFieldsAndPosition(widget.report.id);
|
||
|
|
reportModel.loadSelectedFieldsAndPosition(widget.report.id).then((value) {
|
||
|
|
print("report value => $value");
|
||
|
|
if (value != null) {
|
||
|
|
_initialDisplayFields = value.fieldSelection;
|
||
|
|
_initialFields = value.fieldPosition;
|
||
|
|
} else {
|
||
|
|
_initialDisplayFields = _report.displayFields;
|
||
|
|
_initialFields = _report.fields;
|
||
|
|
}
|
||
|
|
|
||
|
|
_initialDisplayFields.asMap().forEach((key, value) {
|
||
|
|
_initialFields.asMap().forEach((key, fvalue) {
|
||
|
|
if (value == fvalue.name) {
|
||
|
|
displayFields.add(fvalue);
|
||
|
|
if (fvalue.aggFun != '') {
|
||
|
|
var convertField = fvalue.name + '_' + fvalue.aggFun;
|
||
|
|
cellfields.add(convertField);
|
||
|
|
}
|
||
|
|
if (fvalue.aggFun == '') {
|
||
|
|
cellfields.add(value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
_initialfieldList.add(value);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
setState(() {
|
||
|
|
this.report = _report;
|
||
|
|
});
|
||
|
|
|
||
|
|
_loadData();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
_loadData() {
|
||
|
|
var reportModel = Provider.of<ReportModel>(context, listen: false);
|
||
|
|
reportModel.getReportData(report, limit, offset).then((value) {
|
||
|
|
setState(() {
|
||
|
|
if (value == null || value.length < limit) {
|
||
|
|
_endOfData = true;
|
||
|
|
}
|
||
|
|
dataList.addAll(value);
|
||
|
|
_isLoading = false;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
ScrollController _controller;
|
||
|
|
|
||
|
|
_scrollListener() {
|
||
|
|
if (_controller.offset >= _controller.position.maxScrollExtent &&
|
||
|
|
!_controller.position.outOfRange) {
|
||
|
|
setState(() {
|
||
|
|
offset += limit;
|
||
|
|
if (!_endOfData) _loadData();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Widget _buildPopupMenu() {
|
||
|
|
return PopupMenuButton(
|
||
|
|
onSelected: (s) {
|
||
|
|
if (s == 1) {
|
||
|
|
// var reportModel = Provider.of<ReportModel>(context, listen: false);
|
||
|
|
// reportModel.downloadReportData(report);
|
||
|
|
_download();
|
||
|
|
} else if (s == 2) {}
|
||
|
|
},
|
||
|
|
itemBuilder: (context) => [
|
||
|
|
PopupMenuItem(
|
||
|
|
value: 1,
|
||
|
|
child: Text("Download"),
|
||
|
|
),
|
||
|
|
PopupMenuItem(
|
||
|
|
value: 2,
|
||
|
|
child: Text("Clear setting"),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
var reportModel = Provider.of<ReportModel>(context, listen: false);
|
||
|
|
fieldList = _initialfieldList;
|
||
|
|
print("report fieldList => $fieldList");
|
||
|
|
print("report sortColumnIndex => $sortColumnIndex");
|
||
|
|
|
||
|
|
return LocalProgress(
|
||
|
|
inAsyncCall: _isLoading,
|
||
|
|
child: Scaffold(
|
||
|
|
appBar: AppBar(
|
||
|
|
actions: <Widget>[
|
||
|
|
IconButton(
|
||
|
|
onPressed: () {
|
||
|
|
Navigator.of(context).push(MaterialPageRoute(
|
||
|
|
builder: (_) => ReportFilterListPage(report, (data) {
|
||
|
|
dataList = [];
|
||
|
|
setState(() {
|
||
|
|
dataList = data;
|
||
|
|
});
|
||
|
|
})));
|
||
|
|
},
|
||
|
|
iconSize: 30,
|
||
|
|
icon: Icon(Icons.filter_list),
|
||
|
|
),
|
||
|
|
IconButton(
|
||
|
|
onPressed: () async {
|
||
|
|
List flist = await Navigator.push<List>(
|
||
|
|
context,
|
||
|
|
MaterialPageRoute(
|
||
|
|
builder: (context) => ReportFieldListPage(
|
||
|
|
id: widget.report.id,
|
||
|
|
fields: report.fields,
|
||
|
|
selectedDisplayFields: fieldList,
|
||
|
|
)),
|
||
|
|
);
|
||
|
|
|
||
|
|
fieldList = [];
|
||
|
|
cellfields = [];
|
||
|
|
displayFields = [];
|
||
|
|
setState(() {
|
||
|
|
fieldList = flist;
|
||
|
|
fieldList.asMap().forEach((key, value) {
|
||
|
|
_initialFields.asMap().forEach((key, fvalue) {
|
||
|
|
if (value == fvalue.name) {
|
||
|
|
displayFields.add(fvalue);
|
||
|
|
if (fvalue.aggFun != '') {
|
||
|
|
var convertField = fvalue.name + '_' + fvalue.aggFun;
|
||
|
|
cellfields.add(convertField);
|
||
|
|
}
|
||
|
|
if (fvalue.aggFun == '') {
|
||
|
|
cellfields.add(value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
},
|
||
|
|
iconSize: 30,
|
||
|
|
icon: Icon(Icons.list),
|
||
|
|
),
|
||
|
|
_buildPopupMenu()
|
||
|
|
],
|
||
|
|
backgroundColor: primaryColor,
|
||
|
|
title: Text(
|
||
|
|
report == null ? "" : report.display,
|
||
|
|
style: Provider.of<LanguageModel>(context).isEng
|
||
|
|
? TextStyle(fontSize: 18)
|
||
|
|
: TextStyle(fontSize: 18, fontFamily: 'MyanmarUnicode'),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
body: _isLoading
|
||
|
|
? Container()
|
||
|
|
: SingleChildScrollView(
|
||
|
|
controller: _controller,
|
||
|
|
scrollDirection: Axis.vertical,
|
||
|
|
child: SingleChildScrollView(
|
||
|
|
scrollDirection: Axis.horizontal,
|
||
|
|
child: MyDataTable(
|
||
|
|
columnSpacing: 10,
|
||
|
|
sortAscending: this.sort,
|
||
|
|
sortColumnIndex: this.sortColumnIndex,
|
||
|
|
columns: getReportColumn(reportModel, this.displayFields),
|
||
|
|
rows: getReportRow(this.dataList),
|
||
|
|
oddLine: tableRowOdd,
|
||
|
|
evenLine: tableRowEven,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
onSortColumn(ReportModel reportModel, int columnIndex, bool ascending,
|
||
|
|
String fieldName) {
|
||
|
|
if (columnIndex == this.sortColumnIndex) {
|
||
|
|
if (ascending) {
|
||
|
|
var str = fieldName + " " + "asc";
|
||
|
|
List sorts = [];
|
||
|
|
sorts.add(str);
|
||
|
|
this.report.id = widget.report.id;
|
||
|
|
this.report.sorts = sorts;
|
||
|
|
reportModel.getReportData(report, this.limit, 0).then((value) {
|
||
|
|
setState(() {
|
||
|
|
dataList = value;
|
||
|
|
_isLoading = false;
|
||
|
|
this.offset = 0;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
var str = fieldName + " " + "desc";
|
||
|
|
List sorts = [];
|
||
|
|
sorts.add(str);
|
||
|
|
this.report.id = widget.report.id;
|
||
|
|
this.report.sorts = sorts;
|
||
|
|
Provider.of<ReportModel>(context)
|
||
|
|
.getReportData(report, this.limit, 0)
|
||
|
|
.then((value) {
|
||
|
|
setState(() {
|
||
|
|
dataList = value;
|
||
|
|
_isLoading = false;
|
||
|
|
this.offset = 0;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
List<MyDataColumn> getReportColumn(
|
||
|
|
ReportModel reportModel, List<Field> colList) {
|
||
|
|
return colList.map((p) {
|
||
|
|
var r = MyDataColumn(
|
||
|
|
label: Text(
|
||
|
|
p.displayName,
|
||
|
|
style: TextStyle(
|
||
|
|
fontSize: 16, color: Colors.black, fontWeight: FontWeight.bold),
|
||
|
|
),
|
||
|
|
onSort: (columnIndex, ascending) {
|
||
|
|
setState(() {
|
||
|
|
sort = !sort;
|
||
|
|
sortColumnIndex = columnIndex;
|
||
|
|
});
|
||
|
|
onSortColumn(reportModel, columnIndex, ascending, p.name);
|
||
|
|
},
|
||
|
|
numeric:
|
||
|
|
p.dataType == 'integer' || p.dataType == 'float' ? true : false,
|
||
|
|
);
|
||
|
|
return r;
|
||
|
|
}).toList()
|
||
|
|
..insert(0, MyDataColumn(label: Text("Sr")));
|
||
|
|
}
|
||
|
|
|
||
|
|
List<MyDataRow> getReportRow(List rowList) {
|
||
|
|
int index = 0;
|
||
|
|
return rowList.map((p) {
|
||
|
|
var r = MyDataRow(cells: getDataCell(p, this.cellfields, ++index));
|
||
|
|
return r;
|
||
|
|
}).toList();
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<String> _findLocalPath() async {
|
||
|
|
var platform = Theme.of(context).platform;
|
||
|
|
final directory = platform == TargetPlatform.android
|
||
|
|
? await getExternalStorageDirectory()
|
||
|
|
: await getApplicationDocumentsDirectory();
|
||
|
|
return directory.path;
|
||
|
|
}
|
||
|
|
|
||
|
|
_download() async {
|
||
|
|
await _prepare();
|
||
|
|
|
||
|
|
var reportModel = Provider.of<ReportModel>(context, listen: false);
|
||
|
|
String payload = await reportModel.getEscapeJson(report);
|
||
|
|
|
||
|
|
print("downloader Path:$_localPath");
|
||
|
|
String id = await FlutterDownloader.enqueue(
|
||
|
|
url: "http://petrok.mokkon.com:8082/api/report-pdf/${report.object}",
|
||
|
|
headers: {"payload": payload},
|
||
|
|
savedDir: _localPath,
|
||
|
|
showNotification: true,
|
||
|
|
openFileFromNotification: true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
List<MyDataCell> getDataCell(data, List fields, int index) {
|
||
|
|
return fields.map((field) {
|
||
|
|
var cell = MyDataCell(Text(
|
||
|
|
'${data[field] == null ? "" : data[field]}',
|
||
|
|
));
|
||
|
|
return cell;
|
||
|
|
}).toList()
|
||
|
|
..insert(0, MyDataCell(Text("$index")));
|
||
|
|
}
|