clean up sheet_viewer_page, add two page turn and fullscreen exit on top-right touch
This commit is contained in:
@@ -31,11 +31,12 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
||||
final log = Logger("SheetViewerPage");
|
||||
final StorageHelper storageHelper = StorageHelper();
|
||||
|
||||
int page = 1;
|
||||
int currentPageNumber = 1;
|
||||
int numPages = 1;
|
||||
late Future<bool> documentLoaded;
|
||||
PdfDocument? document;
|
||||
bool paintMode = false;
|
||||
Pages? pages;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -84,20 +85,16 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
||||
|
||||
void turnPage(int numTurns) {
|
||||
setState(() {
|
||||
page += numTurns;
|
||||
page = page.clamp(1, numPages);
|
||||
currentPageNumber += numTurns;
|
||||
currentPageNumber = currentPageNumber.clamp(1, numPages);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BtPedalShortcuts(
|
||||
onTurnPageForward: () => turnPage(1),
|
||||
onTurnPageBackward: () => turnPage(-1),
|
||||
child: Scaffold(
|
||||
appBar: widget.config.fullscreen
|
||||
? null
|
||||
: AppBar(
|
||||
AppBar? buildAppBar() {
|
||||
if (widget.config.fullscreen) {
|
||||
return null;
|
||||
}
|
||||
return AppBar(
|
||||
title: Text(widget.sheet.name),
|
||||
actions: [
|
||||
IconButton(
|
||||
@@ -124,18 +121,31 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
widget.config.twoPageMode
|
||||
? Icons.filter_1
|
||||
: Icons.filter_2,
|
||||
widget.config.twoPageMode ? Icons.filter_1 : Icons.filter_2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BtPedalShortcuts(
|
||||
onTurnPageForward: () => turnPage(1),
|
||||
onTurnPageBackward: () => turnPage(-1),
|
||||
child: Scaffold(
|
||||
appBar: buildAppBar(),
|
||||
body: FutureBuilder(
|
||||
future: documentLoaded,
|
||||
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
|
||||
if (snapshot.hasData && document != null) {
|
||||
numPages = document!.pages.length;
|
||||
pages = Pages(
|
||||
document: document!,
|
||||
numPages: numPages,
|
||||
config: widget.config,
|
||||
currentPageNumber: currentPageNumber,
|
||||
);
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
@@ -143,127 +153,22 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
||||
children: [
|
||||
Visibility(
|
||||
visible: !paintMode,
|
||||
child: GestureDetector(
|
||||
onTapUp: (TapUpDetails details) {
|
||||
// Get the size of the screen
|
||||
final screenWidth = MediaQuery.of(
|
||||
context,
|
||||
).size.width;
|
||||
|
||||
// print("Touch at y = ${details.localPosition.dy}");
|
||||
// print("Touch at x = ${details.localPosition.dx}");
|
||||
// print("Screenwidth = ${screenWidth}");
|
||||
// Check where the user tapped
|
||||
if (details.localPosition.dy < 100) {
|
||||
// TODO
|
||||
setState(() {
|
||||
child: TouchablePages(
|
||||
pages: pages!,
|
||||
onToggleFullscreen: () {
|
||||
toggleFullscreen();
|
||||
});
|
||||
} else if (details.localPosition.dx <
|
||||
screenWidth / 2) {
|
||||
// Left half of the screen
|
||||
turnPage(-1);
|
||||
} else {
|
||||
// Right half of the screen
|
||||
turnPage(1);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 0,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
PdfPageView(
|
||||
key: ValueKey(page),
|
||||
document: document,
|
||||
pageNumber: page,
|
||||
maximumDpi: 300,
|
||||
alignment: widget.config.twoPageMode
|
||||
? Alignment.centerRight
|
||||
: Alignment.center,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding: EdgeInsets.only(bottom: 5),
|
||||
child: Text('$page / $numPages'),
|
||||
onExitSheetViewer: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
onTurnPage: (int numTurns) {
|
||||
turnPage(numTurns);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: widget.config.twoPageMode == true,
|
||||
child: Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
PdfPageView(
|
||||
key: ValueKey(page),
|
||||
document: document,
|
||||
pageNumber: page + 1,
|
||||
maximumDpi: 300,
|
||||
alignment: Alignment.centerLeft,
|
||||
// alignment: Alignment.center,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding: EdgeInsets.only(bottom: 5),
|
||||
child: Text(
|
||||
'${page + 1} / $numPages',
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Positioned.fill(
|
||||
Visibility(
|
||||
visible: paintMode,
|
||||
child: SizedBox.expand(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final maxSize = Size(
|
||||
constraints.maxWidth,
|
||||
constraints.maxHeight,
|
||||
);
|
||||
final pageSizeUnscaled = document!.pages
|
||||
.elementAt(page)
|
||||
.size;
|
||||
final pageSizeScaled = calcScaledPageSize(
|
||||
maxSize,
|
||||
pageSizeUnscaled,
|
||||
);
|
||||
return DrawingBoard(
|
||||
background: SizedBox(
|
||||
width: pageSizeScaled.width,
|
||||
height: pageSizeScaled.height,
|
||||
child: PdfPageView(
|
||||
document: document,
|
||||
pageNumber: page,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
),
|
||||
// showDefaultTools: true,
|
||||
// showDefaultActions: true,
|
||||
boardConstrained: true,
|
||||
minScale: 1,
|
||||
maxScale: 3,
|
||||
alignment: Alignment.topRight,
|
||||
boardBoundaryMargin: EdgeInsets.all(0),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
child: PaintablePages(pages: pages!),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -287,25 +192,183 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Size calcScaledPageSize(Size parentSize, Size pageSize) {
|
||||
typedef PageturnCallback = void Function(int numTurns);
|
||||
|
||||
class TouchablePages extends StatelessWidget {
|
||||
final Pages pages;
|
||||
final VoidCallback onToggleFullscreen;
|
||||
final VoidCallback onExitSheetViewer;
|
||||
final PageturnCallback onTurnPage;
|
||||
|
||||
const TouchablePages({
|
||||
super.key,
|
||||
required this.pages,
|
||||
required this.onToggleFullscreen,
|
||||
required this.onExitSheetViewer,
|
||||
required this.onTurnPage,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
behavior:
|
||||
HitTestBehavior.opaque, // Also register when outside of pdf pages
|
||||
onTapUp: (TapUpDetails details) {
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
final pixelsPerInch =
|
||||
mediaQuery.devicePixelRatio *
|
||||
160; // 160 dpi = 1 logical inch baseline
|
||||
final pixelsPerCm = pixelsPerInch / 2.54;
|
||||
|
||||
final touchAreaWidth = mediaQuery.size.width;
|
||||
|
||||
if (details.localPosition.dy < 2 * pixelsPerCm &&
|
||||
details.localPosition.dx >= touchAreaWidth - 2 * pixelsPerCm &&
|
||||
pages.config.fullscreen) {
|
||||
onExitSheetViewer();
|
||||
} else if (details.localPosition.dy < 2 * pixelsPerCm) {
|
||||
onToggleFullscreen();
|
||||
} else if (details.localPosition.dx < touchAreaWidth / 4 &&
|
||||
pages.config.twoPageMode) {
|
||||
onTurnPage(-2);
|
||||
} else if (details.localPosition.dx < touchAreaWidth / 2) {
|
||||
onTurnPage(-1);
|
||||
} else if (details.localPosition.dx > touchAreaWidth * 3 / 4 &&
|
||||
pages.config.twoPageMode) {
|
||||
onTurnPage(2);
|
||||
} else {
|
||||
onTurnPage(1);
|
||||
}
|
||||
},
|
||||
child: pages,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaintablePages extends StatelessWidget {
|
||||
final Pages pages;
|
||||
|
||||
const PaintablePages({super.key, required this.pages});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox.expand(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final maxSize = Size(constraints.maxWidth, constraints.maxHeight);
|
||||
final pageSizeScaled = pages.calcCurrentPageSizeScaled(maxSize);
|
||||
return DrawingBoard(
|
||||
background: SizedBox(
|
||||
width: pageSizeScaled.width,
|
||||
height: pageSizeScaled.height,
|
||||
child: pages,
|
||||
),
|
||||
// showDefaultTools: true,
|
||||
// showDefaultActions: true,
|
||||
boardConstrained: true,
|
||||
minScale: 1,
|
||||
maxScale: 3,
|
||||
alignment: Alignment.topRight,
|
||||
boardBoundaryMargin: EdgeInsets.all(0),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Pages extends StatelessWidget {
|
||||
final PdfDocument document;
|
||||
final int numPages;
|
||||
final int currentPageNumber;
|
||||
final Config config;
|
||||
|
||||
const Pages({
|
||||
super.key,
|
||||
required this.document,
|
||||
required this.numPages,
|
||||
required this.currentPageNumber,
|
||||
required this.config,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 0,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
PdfPageView(
|
||||
key: ValueKey(currentPageNumber),
|
||||
document: document,
|
||||
pageNumber: currentPageNumber,
|
||||
maximumDpi: 300,
|
||||
alignment: config.twoPageMode
|
||||
? Alignment.centerRight
|
||||
: Alignment.center,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding: EdgeInsets.only(bottom: 5),
|
||||
child: Text('$currentPageNumber / $numPages'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: config.twoPageMode == true,
|
||||
child: Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
PdfPageView(
|
||||
key: ValueKey(currentPageNumber),
|
||||
document: document,
|
||||
pageNumber: currentPageNumber + 1,
|
||||
maximumDpi: 300,
|
||||
alignment: Alignment.centerLeft,
|
||||
// alignment: Alignment.center,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding: EdgeInsets.only(bottom: 5),
|
||||
child: Text('${currentPageNumber + 1} / $numPages'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Size calcCurrentPageSizeScaled(Size parentSize) {
|
||||
return _calcScaledPageSize(parentSize, _getCurrentPageSizeUnscaled());
|
||||
}
|
||||
|
||||
Size _getCurrentPageSizeUnscaled() {
|
||||
return document.pages.elementAt(currentPageNumber).size;
|
||||
}
|
||||
|
||||
Size _calcScaledPageSize(Size parentSize, Size pageSize) {
|
||||
// page restricted by height
|
||||
log.info("ParentSize: ${parentSize.width}, ${parentSize.height}");
|
||||
log.info("ParentSizeRatio: ${parentSize.aspectRatio}");
|
||||
log.info("PageSizeRatio: ${pageSize.aspectRatio}");
|
||||
if (parentSize.aspectRatio > pageSize.aspectRatio) {
|
||||
log.info("Restricted by height");
|
||||
final height = parentSize.height;
|
||||
final width = height * pageSize.aspectRatio;
|
||||
log.info("Size: $width, $height");
|
||||
return Size(width, height);
|
||||
}
|
||||
// page restricted by width
|
||||
else {
|
||||
log.info("Restricted by height");
|
||||
final width = parentSize.width;
|
||||
final height = width / pageSize.aspectRatio;
|
||||
log.info("Size: $width, $height");
|
||||
return Size(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user