added download from excel and zip in frontend
This commit is contained in:
@@ -16,6 +16,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.model.Questionnaire;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.model.QuestionnaireCustomer;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.utils.QuestionnaireJsonParser.MatrixAnswer;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.utils.QuestionnaireJsonParser.QuestionJsonObj;
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,9 @@ public class ExcelUtils {
|
||||
|
||||
public Optional<byte[]> create(QuestionnaireCustomer customer, List<Questionnaire> questionnaires) {
|
||||
LOG.debug("Create excel file for customer " + customer);
|
||||
// TODO: implement excel export
|
||||
if(customer == null || questionnaires.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); XSSFWorkbook workbook = new XSSFWorkbook()) {
|
||||
|
||||
@@ -176,12 +179,7 @@ public class ExcelUtils {
|
||||
if (!answer.selected()) {
|
||||
continue;
|
||||
}
|
||||
int index = 0;
|
||||
for (int i = 0; i < answerOpts.size(); i++) {
|
||||
if (answer.answer().equalsIgnoreCase(answerOpts.get(i).answer())) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
int index = getMatrixAnswerIndex(answerOpts, answer);
|
||||
var cell = questionRow.createCell(1 + index);
|
||||
cell.setCellType(CellType.BOOLEAN);
|
||||
cell.setCellValue(answer.selected());
|
||||
@@ -190,4 +188,14 @@ public class ExcelUtils {
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private int getMatrixAnswerIndex(List<MatrixAnswer> answerOpts, MatrixAnswer answer) {
|
||||
int index = 0;
|
||||
for (int i = 0; i < answerOpts.size(); i++) {
|
||||
if (answer.answer().equalsIgnoreCase(answerOpts.get(i).answer())) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,17 +29,17 @@ import com.drew.metadata.exif.ExifIFD0Directory;
|
||||
*/
|
||||
|
||||
public interface ImageHandler {
|
||||
static final Log LOG = LogFactory.getLog(ImageHandler.class);
|
||||
Log LOG = LogFactory.getLog(ImageHandler.class);
|
||||
|
||||
/**
|
||||
* Reads image bytes and returns a BufferedImage with correct EXIF orientation applied.
|
||||
*/
|
||||
default BufferedImage readImageWithCorrectOrientation(byte[] imageBytes) throws IOException {
|
||||
int orientation = getExifOrientation(imageBytes);
|
||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes));
|
||||
if (image == null) {
|
||||
throw new IOException("Failed to read image from byte array");
|
||||
}
|
||||
int orientation = getExifOrientation(imageBytes);
|
||||
return applyOrientation(image, orientation);
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,9 @@ public class PdfUtils implements ImageHandler {
|
||||
// Return remaining text starting from current word
|
||||
StringBuilder remaining = new StringBuilder(line);
|
||||
for (int i = wordIndex; i < words.length; i++) {
|
||||
if (!remaining.isEmpty()) remaining.append(" ");
|
||||
if (!remaining.isEmpty()) {
|
||||
remaining.append(" ");
|
||||
}
|
||||
remaining.append(words[i]);
|
||||
}
|
||||
return remaining.toString();
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import jakarta.json.*;
|
||||
import jakarta.json.JsonValue.ValueType;
|
||||
import jakarta.json.stream.JsonParsingException;
|
||||
|
||||
/**
|
||||
@@ -74,10 +75,10 @@ public class QuestionnaireJsonParser {
|
||||
public record QuestionJsonObj(String id, String title, int order, String type, String data) {
|
||||
|
||||
public List<MatrixQuestion> getMatrixAnswer() {
|
||||
return getValue("questions", () -> null, (questions) -> {
|
||||
return getValue("questions", () -> null, matrixQuestions -> {
|
||||
var retVal = new ArrayList<MatrixQuestion>();
|
||||
|
||||
for (var question : questions) {
|
||||
for (var question : matrixQuestions) {
|
||||
var questionObj = question.asJsonObject();
|
||||
var id = questionObj.getString("id");
|
||||
var title = questionObj.getString("title");
|
||||
@@ -101,19 +102,23 @@ public class QuestionnaireJsonParser {
|
||||
}
|
||||
|
||||
public Integer getNumberAnswer() {
|
||||
return getValue(() -> null, (answers) -> {
|
||||
return getValue(() -> null, answers -> {
|
||||
for (var answer : answers) {
|
||||
var answerObj = answer.asJsonObject();
|
||||
if (answerObj.getBoolean("selected")) {
|
||||
var value = answerObj.get("answer");
|
||||
if (value.getValueType() == ValueType.NUMBER) {
|
||||
return answerObj.getInt("answer");
|
||||
}
|
||||
return Integer.parseInt(answerObj.getString("answer"));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public String getSingleAnswer() {
|
||||
return getValue(() -> "", (answers) -> {
|
||||
return getValue(() -> "", answers -> {
|
||||
for (var answer : answers) {
|
||||
var answerObj = answer.asJsonObject();
|
||||
if (answerObj.getBoolean("selected")) {
|
||||
@@ -125,7 +130,7 @@ public class QuestionnaireJsonParser {
|
||||
}
|
||||
|
||||
public List<String> getMultiAnswer() {
|
||||
return getValue(() -> List.of(), (answers) -> {
|
||||
return getValue(() -> List.of(), answers -> {
|
||||
List<String> retVal = new ArrayList<>();
|
||||
for (var answer : answers) {
|
||||
var answerObj = answer.asJsonObject();
|
||||
|
||||
@@ -246,7 +246,7 @@ class ExcelUtilsTest implements TestAble {
|
||||
private Questionnaire createQuestionnaire(Date date, String questions) {
|
||||
return new Questionnaire.Builder()
|
||||
.questionnaireDate(date)
|
||||
.questions(QuestionnaireJsonParserTest.testJson1)
|
||||
.questions(QuestionnaireJsonParserTest.TEST_JSON_1)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@ public class QuestionnaireJsonParserTest {
|
||||
@Test
|
||||
public void testJson1() {
|
||||
var parser = new QuestionnaireJsonParser();
|
||||
boolean retVal = parser.parse(testJson1);
|
||||
boolean retVal = parser.parse(TEST_JSON_1);
|
||||
assertTrue(retVal);
|
||||
var questions = parser.getQuestions();
|
||||
assertEquals(10, questions.size());
|
||||
}
|
||||
|
||||
|
||||
public static final String testJson1 = """
|
||||
public static final String TEST_JSON_1 = """
|
||||
[
|
||||
{
|
||||
"id": "question1",
|
||||
|
||||
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