138 lines
4.0 KiB
Dart
138 lines
4.0 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:pdfrx/pdfrx.dart';
|
|
|
|
import '../../../core/models/config.dart';
|
|
|
|
/// Displays PDF pages with optional two-page mode.
|
|
class PdfPageDisplay extends StatelessWidget {
|
|
final PdfDocument document;
|
|
final int numPages;
|
|
final int currentPageNumber;
|
|
final Config config;
|
|
|
|
const PdfPageDisplay({
|
|
super.key,
|
|
required this.document,
|
|
required this.numPages,
|
|
required this.currentPageNumber,
|
|
required this.config,
|
|
});
|
|
|
|
/// Whether two-page mode is active and we have enough pages.
|
|
bool get _showTwoPages => config.twoPageMode && numPages >= 2;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [_buildLeftPage(), if (_showTwoPages) _buildRightPage()],
|
|
);
|
|
}
|
|
|
|
Widget _buildLeftPage() {
|
|
return Expanded(
|
|
child: Stack(
|
|
children: [
|
|
PdfPageView(
|
|
key: ValueKey(currentPageNumber),
|
|
document: document,
|
|
pageNumber: currentPageNumber,
|
|
maximumDpi: 300,
|
|
alignment: _showTwoPages ? Alignment.centerRight : Alignment.center,
|
|
),
|
|
_buildPageIndicator(currentPageNumber),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildRightPage() {
|
|
final rightPageNumber = currentPageNumber + 1;
|
|
|
|
return Expanded(
|
|
child: Stack(
|
|
children: [
|
|
PdfPageView(
|
|
key: ValueKey(rightPageNumber),
|
|
document: document,
|
|
pageNumber: rightPageNumber,
|
|
maximumDpi: 300,
|
|
alignment: Alignment.centerLeft,
|
|
),
|
|
_buildPageIndicator(rightPageNumber),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildPageIndicator(int pageNumber) {
|
|
return Positioned.fill(
|
|
child: Container(
|
|
alignment: Alignment.bottomCenter,
|
|
padding: const EdgeInsets.only(bottom: 5),
|
|
child: Text('$pageNumber / $numPages'),
|
|
),
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Page Size Calculations
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// Calculates scaled page sizes for the current view.
|
|
///
|
|
/// Returns a tuple of (leftPageSize, rightPageSize).
|
|
/// rightPageSize is null when not in two-page mode.
|
|
(Size, Size?) calculateScaledPageSizes(Size parentSize) {
|
|
if (config.twoPageMode) {
|
|
return _calculateTwoPageSizes(parentSize);
|
|
}
|
|
return (_calculateSinglePageSize(parentSize), null);
|
|
}
|
|
|
|
(Size, Size?) _calculateTwoPageSizes(Size parentSize) {
|
|
final leftSize = _getUnscaledPageSize(currentPageNumber);
|
|
final rightSize = numPages > currentPageNumber
|
|
? _getUnscaledPageSize(currentPageNumber + 1)
|
|
: leftSize;
|
|
|
|
// Combine pages for scaling calculation
|
|
final combinedSize = Size(
|
|
leftSize.width + rightSize.width,
|
|
max(leftSize.height, rightSize.height),
|
|
);
|
|
|
|
final scaledCombined = _scaleToFit(parentSize, combinedSize);
|
|
final scaleFactor = scaledCombined.width / combinedSize.width;
|
|
|
|
return (leftSize * scaleFactor, rightSize * scaleFactor);
|
|
}
|
|
|
|
Size _calculateSinglePageSize(Size parentSize) {
|
|
return _scaleToFit(parentSize, _getUnscaledPageSize(currentPageNumber));
|
|
}
|
|
|
|
Size _getUnscaledPageSize(int pageNumber) {
|
|
return document.pages.elementAt(pageNumber - 1).size;
|
|
}
|
|
|
|
/// Scales a page size to fit within parent bounds while maintaining aspect ratio.
|
|
Size _scaleToFit(Size parentSize, Size pageSize) {
|
|
// Determine if height or width is the limiting factor
|
|
if (parentSize.aspectRatio > pageSize.aspectRatio) {
|
|
// Constrained by height
|
|
final height = parentSize.height;
|
|
final width = height * pageSize.aspectRatio;
|
|
return Size(width, height);
|
|
} else {
|
|
// Constrained by width
|
|
final width = parentSize.width;
|
|
final height = width / pageSize.aspectRatio;
|
|
return Size(width, height);
|
|
}
|
|
}
|
|
}
|