added download from excel and zip in frontend
This commit is contained in:
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 506 B |
@@ -7,6 +7,8 @@ abstract interface class QuestionnaireCustomerController {
|
||||
Future<QuestionnaireCustomerDto?> get({required int id});
|
||||
|
||||
Future<List<int>> export({required int customerId, int? questionnaireId});
|
||||
|
||||
Future<List<int>> exportAll();
|
||||
}
|
||||
|
||||
class QuestionnaireCustomerControllerImpl extends BaseController implements QuestionnaireCustomerController {
|
||||
@@ -39,4 +41,10 @@ class QuestionnaireCustomerControllerImpl extends BaseController implements Ques
|
||||
}
|
||||
return runGetBytesWithAuth(uriStr);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<int>> exportAll() {
|
||||
String uriStr = '${uriUtils.getBaseUrl()}$path/exportall';
|
||||
return runGetBytesWithAuth(uriStr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:fotodocumentation/dto/picture_dto.dart';
|
||||
import 'package:fotodocumentation/l10n/app_localizations.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/customer_back_button.dart';
|
||||
import 'package:fotodocumentation/pages/foto/customer/foto_picture_fullscreen_dialog.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/evaluation_circle.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/general_error_widget.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/page_header_widget.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/waiting_widget.dart';
|
||||
@@ -306,25 +307,28 @@ class _FotoPictureWidgetState extends State<FotoPictureWidget> {
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_evaluationCircle(
|
||||
key: const Key("evaluation_good"),
|
||||
EvaluationCircleWidget(
|
||||
buttonKey: const Key("evaluation_good"),
|
||||
color: _generalStyle.evaluationGoodColor,
|
||||
value: 1,
|
||||
selected: dto.evaluation == 1,
|
||||
doUpdate: (circle) => _actionUpdateEvaluation(circle.value),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_evaluationCircle(
|
||||
key: const Key("evaluation_middle"),
|
||||
EvaluationCircleWidget(
|
||||
buttonKey: const Key("evaluation_middle"),
|
||||
color: _generalStyle.evaluationMiddleColor,
|
||||
value: 2,
|
||||
selected: dto.evaluation == 2,
|
||||
doUpdate: (circle) => _actionUpdateEvaluation(circle.value),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_evaluationCircle(
|
||||
key: const Key("evaluation_bad"),
|
||||
EvaluationCircleWidget(
|
||||
buttonKey: const Key("evaluation_bad"),
|
||||
color: _generalStyle.evaluationBadColor,
|
||||
value: 3,
|
||||
selected: dto.evaluation == 3,
|
||||
doUpdate: (circle) => _actionUpdateEvaluation(circle.value),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -334,28 +338,6 @@ class _FotoPictureWidgetState extends State<FotoPictureWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _evaluationCircle({
|
||||
required Key key,
|
||||
required Color color,
|
||||
required int value,
|
||||
required bool selected,
|
||||
}) {
|
||||
return InkWell(
|
||||
key: key,
|
||||
onTap: () async => _actionUpdateEvaluation(value),
|
||||
customBorder: const CircleBorder(),
|
||||
child: Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
shape: BoxShape.circle,
|
||||
border: selected ? Border.all(color: _generalStyle.secondaryWidgetBackgroundColor, width: 3) : null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Bottom navigation buttons
|
||||
Widget _bottomNavigationWidget(List<PictureDto> pictures, PictureDto selectedPicture) {
|
||||
pictures.sort((a, b) => a.pictureDate.compareTo(b.pictureDate));
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:fotodocumentation/pages/ui_utils/component/search_bar_widget.dar
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/waiting_widget.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/general_style.dart';
|
||||
import 'package:fotodocumentation/utils/di_container.dart';
|
||||
import 'package:fotodocumentation/utils/file_download.dart';
|
||||
import 'package:fotodocumentation/utils/global_router.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
@@ -60,7 +61,6 @@ class _QuestionaireCustomerListWidgetState extends State<QuestionaireCustomerLis
|
||||
children: [
|
||||
PageHeaderWidget(text: "FRAGENBOGEN AUSWERTUNG"),
|
||||
//_abcHeaderBar(),
|
||||
const SizedBox(width: 48),
|
||||
SearchBarWidget(
|
||||
searchController: _searchController,
|
||||
onSearch: (text) async => actionSearch(text),
|
||||
@@ -68,6 +68,16 @@ class _QuestionaireCustomerListWidgetState extends State<QuestionaireCustomerLis
|
||||
Expanded(
|
||||
child: _customerListWidget(),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top:24.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
_downloadButton(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -237,6 +247,34 @@ class _QuestionaireCustomerListWidgetState extends State<QuestionaireCustomerLis
|
||||
);
|
||||
}
|
||||
|
||||
Widget _downloadButton(BuildContext context) {
|
||||
return ElevatedButton.icon(
|
||||
key: Key("download_all_button"),
|
||||
onPressed: () => _actionDownload(context),
|
||||
iconAlignment: IconAlignment.end,
|
||||
icon: Icon(
|
||||
Icons.file_download_outlined,
|
||||
color: _generalStyle.primaryButtonTextColor,
|
||||
size: 24,
|
||||
),
|
||||
label: Text(
|
||||
"Alle herunterladen",
|
||||
style: TextStyle(
|
||||
fontFamily: _generalStyle.fontFamily,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: _generalStyle.primaryButtonTextColor,
|
||||
),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _generalStyle.secondaryWidgetBackgroundColor,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
shape: const StadiumBorder(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> actionSearch(String text) async {
|
||||
_reloadData();
|
||||
}
|
||||
@@ -250,6 +288,47 @@ class _QuestionaireCustomerListWidgetState extends State<QuestionaireCustomerLis
|
||||
_dtos = _questionnaireCustomerController.getAll(_searchController.text, _selectedLetter ?? "");
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _actionDownload(BuildContext context) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => Dialog(
|
||||
backgroundColor: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(width: 16),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.customerWidgetDownloadInProgress,
|
||||
style: TextStyle(
|
||||
fontFamily: _generalStyle.fontFamily,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
final bytes = await _questionnaireCustomerController.exportAll();
|
||||
final fileName = 'download.zip';
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
await downloadFile(bytes, fileName);
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Widget _abcHeaderBar() {
|
||||
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:fotodocumentation/dto/questionnaire_dto.dart';
|
||||
import 'package:fotodocumentation/l10n/app_localizations.dart';
|
||||
import 'package:fotodocumentation/pages/questionnaire/customer/questionnaire_delete_dialog.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/customer_back_button.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/evaluation_circle.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/general_error_widget.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/page_header_widget.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/component/waiting_widget.dart';
|
||||
@@ -26,7 +27,7 @@ class QuestionaireCustomerWidget extends StatefulWidget {
|
||||
|
||||
class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget> {
|
||||
QuestionnaireCustomerController get _customerController => DiContainer.get();
|
||||
QuestionnaireController get _pictureController => DiContainer.get();
|
||||
QuestionnaireController get _questionnaireController => DiContainer.get();
|
||||
GeneralStyle get _generalStyle => DiContainer.get();
|
||||
|
||||
late Future<QuestionnaireCustomerDto?> _dto;
|
||||
@@ -155,16 +156,7 @@ class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget>
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.customerWidgetHeaderFoto,
|
||||
style: headerStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 45),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Align(
|
||||
@@ -209,7 +201,7 @@ class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget>
|
||||
);
|
||||
|
||||
final dateStr = _dateFormat.format(questionnaireDto.questionnaireDate);
|
||||
final evaluationColor = _generalStyle.evaluationColor(value: questionnaireDto.evaluation);
|
||||
|
||||
return InkWell(
|
||||
key: Key("table_row_${customerDto.id}"),
|
||||
child: Padding(
|
||||
@@ -219,23 +211,9 @@ class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget>
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 70, maxHeight: 70),
|
||||
child:
|
||||
Icon(Icons.abc),
|
||||
/*
|
||||
FIXME: remove me
|
||||
Image.network(
|
||||
headers: {cred.name: cred.value},
|
||||
pictureDto.thumbnailSizeUrl,
|
||||
fit: BoxFit.contain,
|
||||
),*/
|
||||
),
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 45, maxWidth: 45),
|
||||
child: Icon(IconData(0xE800, fontFamily: "MyFlutterApp")),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
@@ -248,14 +226,7 @@ class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget>
|
||||
flex: 1,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: evaluationColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
child: _evalationWidget(questionnaireDto),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@@ -293,6 +264,37 @@ class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _evalationWidget(QuestionnaireDto dto) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
EvaluationCircleWidget(
|
||||
buttonKey: const Key("evaluation_good"),
|
||||
color: _generalStyle.evaluationGoodColor,
|
||||
value: 1,
|
||||
selected: dto.evaluation == 1,
|
||||
doUpdate: (circle) async => _actionUpdateEvaluation(dto, circle.value),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
EvaluationCircleWidget(
|
||||
buttonKey: const Key("evaluation_middle"),
|
||||
color: _generalStyle.evaluationMiddleColor,
|
||||
value: 2,
|
||||
selected: dto.evaluation == 2,
|
||||
doUpdate: (circle) async => _actionUpdateEvaluation(dto, circle.value),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
EvaluationCircleWidget(
|
||||
buttonKey: const Key("evaluation_bad"),
|
||||
color: _generalStyle.evaluationBadColor,
|
||||
value: 3,
|
||||
selected: dto.evaluation == 3,
|
||||
doUpdate: (circle) async => _actionUpdateEvaluation(dto, circle.value),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _downloadButton(BuildContext context, QuestionnaireCustomerDto customerDto) {
|
||||
return ElevatedButton.icon(
|
||||
key: Key("download_all_button"),
|
||||
@@ -321,6 +323,12 @@ class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget>
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _actionUpdateEvaluation(QuestionnaireDto dto, int value) async {
|
||||
dto.evaluation = value;
|
||||
_questionnaireController.updateEvaluation(dto);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _actionDelete(BuildContext context, QuestionnaireCustomerDto customerDto, QuestionnaireDto questionnaireDto) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
@@ -330,7 +338,7 @@ class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget>
|
||||
);
|
||||
|
||||
if (confirmed == true) {
|
||||
_pictureController.delete(questionnaireDto);
|
||||
_questionnaireController.delete(questionnaireDto);
|
||||
setState(() {
|
||||
_dto = _customerController.get(id: widget.customerId);
|
||||
});
|
||||
@@ -365,7 +373,7 @@ class _QuestionaireCustomerWidgetState extends State<QuestionaireCustomerWidget>
|
||||
|
||||
try {
|
||||
final bytes = await _customerController.export(customerId: customerDto.id, questionnaireId: questionnaireDto?.id);
|
||||
final fileName = questionnaireDto != null ? '${customerDto.customerNumber}_${questionnaireDto.id}.pdf' : '${customerDto.customerNumber}.pdf';
|
||||
final fileName = questionnaireDto != null ? '${customerDto.customerNumber}_${questionnaireDto.id}.xlsx' : '${customerDto.customerNumber}.xlsx';
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fotodocumentation/pages/ui_utils/general_style.dart';
|
||||
import 'package:fotodocumentation/utils/di_container.dart';
|
||||
|
||||
class EvaluationCircleWidget extends StatelessWidget {
|
||||
GeneralStyle get _generalStyle => DiContainer.get();
|
||||
|
||||
final Key buttonKey;
|
||||
final Color color;
|
||||
final int value;
|
||||
final bool selected;
|
||||
final Future<void> Function(EvaluationCircleWidget) doUpdate;
|
||||
|
||||
const EvaluationCircleWidget({super.key, required this.buttonKey, required this.color, required this.value, required this.selected, required this.doUpdate});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
key: buttonKey,
|
||||
onTap: () async => doUpdate(this), //_actionUpdateEvaluation(value),
|
||||
customBorder: const CircleBorder(),
|
||||
child: Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
shape: BoxShape.circle,
|
||||
border: selected ? Border.all(color: _generalStyle.secondaryWidgetBackgroundColor, width: 3) : null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,8 @@ class GlobalRouter {
|
||||
|
||||
static final String pathRoot = "/";
|
||||
|
||||
static final String pathFoto = "/foto";
|
||||
static final String pathQuestionnaire = "/fragenbogen";
|
||||
static final String pathFoto = "/fotodokumentation";
|
||||
static final String pathQuestionnaire = "/fragebogen-auswertung";
|
||||
|
||||
static final String pathFotoHome = "$pathFoto/home";
|
||||
static final String pathFotoCustomer = "$pathFoto/customer";
|
||||
|
||||
@@ -122,3 +122,9 @@ flutter:
|
||||
#
|
||||
# For details regarding fonts from package dependencies,
|
||||
# see https://flutter.dev/custom-fonts/#from-packages
|
||||
fonts:
|
||||
- family: MyFlutterApp
|
||||
fonts:
|
||||
- asset: assets/fonts/MyFlutterApp.ttf
|
||||
style: normal
|
||||
|
||||
Reference in New Issue
Block a user