Skip to content

Commit 5a8b94f

Browse files
refactor to use only one pdf viewer
1 parent 2617262 commit 5a8b94f

21 files changed

Lines changed: 257 additions & 894 deletions

File tree

Lines changed: 156 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,171 @@
11
import 'dart:io';
22

33
import 'package:flutter/material.dart';
4+
import 'package:logging/logging.dart';
5+
import 'package:pdfrx/pdfrx.dart';
46
import 'package:printing/printing.dart';
57
import 'package:school_data_hub_flutter/common/theme/app_colors.dart';
8+
import 'package:school_data_hub_flutter/common/widgets/bottom_nav_bar/generic_bottom_nav_bar.dart';
69
import 'package:school_data_hub_flutter/common/widgets/generic_components/generic_app_bar.dart';
710

8-
class PdfViewerPage extends StatelessWidget {
9-
final File pdfFile;
10-
const PdfViewerPage({required this.pdfFile, super.key});
11+
final _log = Logger('PdfViewerPage');
12+
13+
class PdfViewerPage extends StatefulWidget {
14+
final Future<File> Function() pdfGenerator;
15+
final String title;
16+
final IconData iconData;
17+
final bool showZoomButton;
18+
19+
const PdfViewerPage({
20+
required this.pdfGenerator,
21+
this.title = 'PDF Vorschau',
22+
this.iconData = Icons.picture_as_pdf,
23+
this.showZoomButton = false,
24+
super.key,
25+
});
26+
27+
@override
28+
State<PdfViewerPage> createState() => _PdfViewerPageState();
29+
}
30+
31+
class _PdfViewerPageState extends State<PdfViewerPage> {
32+
File? _generatedFile;
33+
34+
@override
35+
void dispose() {
36+
if (_generatedFile?.existsSync() ?? false) {
37+
_generatedFile!.delete();
38+
}
39+
super.dispose();
40+
}
1141

1242
@override
1343
Widget build(BuildContext context) {
14-
return Scaffold(
15-
appBar: const GenericAppBar(
16-
iconData: Icons.print_rounded,
17-
title: 'Pdf Vorschau',
18-
),
19-
20-
body: PdfPreview(
21-
actionBarTheme: PdfActionBarTheme(
22-
backgroundColor: AppColors.backgroundColor,
23-
iconColor: Colors.white,
24-
textStyle: const TextStyle(color: Colors.white),
25-
),
26-
allowSharing: false,
27-
canChangePageFormat: false,
28-
canChangeOrientation: false,
29-
canDebug: false,
30-
// actions: [Icon(Icons.download)],
31-
onPrinted: (context) {
32-
pdfFile.delete();
33-
if (context.mounted) {
34-
Navigator.of(context).pop();
35-
if (context.mounted) {
36-
Navigator.of(context).pop();
37-
}
38-
}
39-
},
40-
build: (format) => pdfFile.readAsBytes(),
41-
actions: [
42-
IconButton(
43-
icon: const Icon(Icons.arrow_back),
44-
onPressed: () {
45-
pdfFile.delete();
46-
if (context.mounted) {
47-
Navigator.of(context).pop();
48-
if (context.mounted) {
49-
Navigator.of(context).pop();
50-
}
51-
}
44+
return FutureBuilder<File>(
45+
future: widget.pdfGenerator(),
46+
builder: (context, snapshot) {
47+
if (snapshot.hasError) {
48+
_log.severe('Failed to generate PDF', snapshot.error);
49+
return Scaffold(
50+
appBar: GenericAppBar(
51+
iconData: widget.iconData,
52+
title: widget.title,
53+
),
54+
body: Center(
55+
child: Column(
56+
mainAxisAlignment: MainAxisAlignment.center,
57+
children: [
58+
const Icon(Icons.error_outline, size: 48, color: Colors.red),
59+
const SizedBox(height: 16),
60+
const Text('Fehler beim Erstellen des PDFs'),
61+
const SizedBox(height: 8),
62+
Text(
63+
snapshot.error.toString(),
64+
style: const TextStyle(fontSize: 12, color: Colors.grey),
65+
textAlign: TextAlign.center,
66+
),
67+
const SizedBox(height: 16),
68+
ElevatedButton(
69+
onPressed: () => Navigator.of(context).pop(),
70+
child: const Text('Zurück'),
71+
),
72+
],
73+
),
74+
),
75+
);
76+
}
77+
78+
if (!snapshot.hasData) {
79+
return Scaffold(
80+
appBar: GenericAppBar(
81+
iconData: widget.iconData,
82+
title: widget.title,
83+
),
84+
body: const Center(
85+
child: Column(
86+
mainAxisAlignment: MainAxisAlignment.center,
87+
children: [
88+
CircularProgressIndicator(),
89+
SizedBox(height: 16),
90+
Text('PDF wird erstellt...'),
91+
],
92+
),
93+
),
94+
);
95+
}
96+
97+
final file = snapshot.data!;
98+
_generatedFile = file;
99+
_log.info('Opening PDF view for file: ${file.path}');
100+
101+
return Scaffold(
102+
appBar: GenericAppBar(
103+
iconData: widget.iconData,
104+
title: widget.title,
105+
),
106+
body: PdfPreview(
107+
actionBarTheme: PdfActionBarTheme(
108+
backgroundColor: AppColors.backgroundColor,
109+
iconColor: Colors.white,
110+
textStyle: const TextStyle(color: Colors.white),
111+
),
112+
allowSharing: true,
113+
allowPrinting: true,
114+
canChangePageFormat: false,
115+
canChangeOrientation: false,
116+
canDebug: false,
117+
useActions: true,
118+
scrollViewDecoration: const BoxDecoration(color: Colors.grey),
119+
pdfPreviewPageDecoration: const BoxDecoration(
120+
color: Colors.white,
121+
boxShadow: [
122+
BoxShadow(
123+
color: Colors.black26,
124+
offset: Offset(0, 2),
125+
blurRadius: 4,
126+
),
127+
],
128+
),
129+
onPrinted: (context) {
130+
if (context.mounted) Navigator.of(context).pop();
52131
},
132+
build: (format) => file.readAsBytes(),
133+
actions: [
134+
IconButton(
135+
icon: const Icon(Icons.arrow_back),
136+
onPressed: () {
137+
if (context.mounted) Navigator.of(context).pop();
138+
},
139+
),
140+
if (widget.showZoomButton)
141+
IconButton(
142+
icon: const Icon(Icons.zoom_in),
143+
onPressed: () {
144+
Navigator.of(context).push(
145+
MaterialPageRoute<void>(
146+
builder: (context) => _PdfZoomableImage(file: file),
147+
),
148+
);
149+
},
150+
),
151+
],
53152
),
54-
],
55-
),
153+
);
154+
},
155+
);
156+
}
157+
}
158+
159+
class _PdfZoomableImage extends StatelessWidget {
160+
final File file;
161+
const _PdfZoomableImage({required this.file});
162+
163+
@override
164+
Widget build(BuildContext context) {
165+
return Scaffold(
166+
appBar: const GenericAppBar(title: 'PDF Zoom', iconData: Icons.zoom_in),
167+
body: PdfViewer.file(file.path),
168+
bottomNavigationBar: const GenericBottomNavBar(),
56169
);
57170
}
58171
}

school_data_hub_flutter/lib/common/services/attendance_pdf_generator.dart

Lines changed: 0 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'dart:io';
22
import 'dart:typed_data';
33

4-
import 'package:flutter/material.dart';
54
import 'package:flutter/services.dart' show rootBundle;
65
import 'package:flutter_it/flutter_it.dart';
76
import 'package:logging/logging.dart';
@@ -11,8 +10,6 @@ import 'package:pdf/widgets.dart' as pw;
1110
import 'package:printing/printing.dart';
1211
import 'package:school_data_hub_client/school_data_hub_client.dart';
1312
import 'package:school_data_hub_flutter/common/services/notification_service.dart';
14-
import 'package:school_data_hub_flutter/common/theme/app_colors.dart';
15-
import 'package:school_data_hub_flutter/common/widgets/generic_components/generic_app_bar.dart';
1613
import 'package:school_data_hub_flutter/core/models/datetime_extensions.dart';
1714
import 'package:school_data_hub_flutter/features/_attendance/domain/attendance_helper.dart';
1815
import 'package:school_data_hub_flutter/features/_attendance/domain/attendance_manager.dart';
@@ -1336,146 +1333,3 @@ class MissedSchooldaysPdfGenerator {
13361333
);
13371334
}
13381335
}
1339-
1340-
class AttendancePdfViewPage extends StatefulWidget {
1341-
final File pdfFile;
1342-
const AttendancePdfViewPage({required this.pdfFile, super.key});
1343-
1344-
@override
1345-
State<AttendancePdfViewPage> createState() => _AttendancePdfViewPageState();
1346-
}
1347-
1348-
class _AttendancePdfViewPageState extends State<AttendancePdfViewPage> {
1349-
@override
1350-
void dispose() {
1351-
// Ensure the file is deleted when the widget is disposed
1352-
// This handles all cases where the page is popped/closed
1353-
if (widget.pdfFile.existsSync()) {
1354-
widget.pdfFile.delete();
1355-
}
1356-
super.dispose();
1357-
}
1358-
1359-
@override
1360-
Widget build(BuildContext context) {
1361-
return Scaffold(
1362-
appBar: const GenericAppBar(
1363-
iconData: Icons.list_alt_rounded,
1364-
title: 'Anwesenheitsliste PDF',
1365-
),
1366-
body: PdfPreview(
1367-
actionBarTheme: PdfActionBarTheme(
1368-
backgroundColor: AppColors.backgroundColor,
1369-
iconColor: Colors.white,
1370-
textStyle: const TextStyle(color: Colors.white),
1371-
),
1372-
allowSharing: true,
1373-
allowPrinting: true,
1374-
canChangePageFormat: false,
1375-
canChangeOrientation: false,
1376-
canDebug: false,
1377-
useActions: true,
1378-
scrollViewDecoration: const BoxDecoration(color: Colors.grey),
1379-
pdfPreviewPageDecoration: const BoxDecoration(
1380-
color: Colors.white,
1381-
boxShadow: [
1382-
BoxShadow(
1383-
color: Colors.black26,
1384-
offset: Offset(0, 2),
1385-
blurRadius: 4,
1386-
),
1387-
],
1388-
),
1389-
onPrinted: (context) {
1390-
// File will be deleted in dispose(), no need to delete here
1391-
if (context.mounted) {
1392-
Navigator.of(context).pop();
1393-
}
1394-
},
1395-
build: (format) => widget.pdfFile.readAsBytes(),
1396-
actions: [
1397-
IconButton(
1398-
icon: const Icon(Icons.arrow_back),
1399-
onPressed: () {
1400-
// File will be deleted in dispose(), no need to delete here
1401-
if (context.mounted) {
1402-
Navigator.of(context).pop();
1403-
}
1404-
},
1405-
),
1406-
],
1407-
),
1408-
);
1409-
}
1410-
}
1411-
1412-
class MissedSchooldaysPdfViewPage extends StatefulWidget {
1413-
final File pdfFile;
1414-
const MissedSchooldaysPdfViewPage({required this.pdfFile, super.key});
1415-
1416-
@override
1417-
State<MissedSchooldaysPdfViewPage> createState() =>
1418-
_MissedSchooldaysPdfViewPageState();
1419-
}
1420-
1421-
class _MissedSchooldaysPdfViewPageState
1422-
extends State<MissedSchooldaysPdfViewPage> {
1423-
@override
1424-
void dispose() {
1425-
// Ensure the file is deleted when the widget is disposed
1426-
if (widget.pdfFile.existsSync()) {
1427-
widget.pdfFile.delete();
1428-
}
1429-
super.dispose();
1430-
}
1431-
1432-
@override
1433-
Widget build(BuildContext context) {
1434-
return Scaffold(
1435-
appBar: const GenericAppBar(
1436-
iconData: Icons.calendar_month_rounded,
1437-
title: 'Fehlzeitenliste PDF',
1438-
),
1439-
body: PdfPreview(
1440-
actionBarTheme: PdfActionBarTheme(
1441-
backgroundColor: AppColors.backgroundColor,
1442-
iconColor: Colors.white,
1443-
textStyle: const TextStyle(color: Colors.white),
1444-
),
1445-
allowSharing: true,
1446-
allowPrinting: true,
1447-
canChangePageFormat: false,
1448-
canChangeOrientation: false,
1449-
canDebug: false,
1450-
useActions: true,
1451-
scrollViewDecoration: const BoxDecoration(color: Colors.grey),
1452-
pdfPreviewPageDecoration: const BoxDecoration(
1453-
color: Colors.white,
1454-
boxShadow: [
1455-
BoxShadow(
1456-
color: Colors.black26,
1457-
offset: Offset(0, 2),
1458-
blurRadius: 4,
1459-
),
1460-
],
1461-
),
1462-
onPrinted: (context) {
1463-
if (context.mounted) {
1464-
Navigator.of(context).pop();
1465-
}
1466-
},
1467-
build: (format) => widget.pdfFile.readAsBytes(),
1468-
actions: [
1469-
IconButton(
1470-
icon: const Icon(Icons.arrow_back),
1471-
onPressed: () {
1472-
if (context.mounted) {
1473-
Navigator.of(context).pop();
1474-
}
1475-
},
1476-
),
1477-
],
1478-
),
1479-
);
1480-
}
1481-
}

0 commit comments

Comments
 (0)