feat: add zoom level listener and scroll thumbs to PDF viewer

This commit is contained in:
insleker 2025-09-17 17:03:07 +08:00
parent 994c1b2569
commit 6652de28bf
3 changed files with 95 additions and 7 deletions

View File

@ -237,4 +237,6 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(container.read(pdfViewModelProvider), 2); expect(container.read(pdfViewModelProvider), 2);
}); });
//TODO: Scroll Thumbs
} }

View File

@ -1,4 +1,3 @@
import 'dart:typed_data';
import 'package:file_selector/file_selector.dart' as fs; import 'package:file_selector/file_selector.dart' as fs;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -197,11 +196,37 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
return name; return name;
} }
void _onControllerChanged() {
if (mounted) {
if (_viewModel.controller.isReady) {
final newZoomLevel = (_viewModel.controller.currentZoom * 100)
.round()
.clamp(10, 800);
if (newZoomLevel != _zoomLevel) {
setState(() {
_zoomLevel = newZoomLevel;
});
}
} else {
// Reset to default zoom level when controller is not ready
if (_zoomLevel != 100) {
setState(() {
_zoomLevel = 100;
});
}
}
}
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// Build areas once with builders; keep these instances stable. // Build areas once with builders; keep these instances stable.
_viewModel = ref.read(pdfViewModelProvider.notifier); _viewModel = ref.read(pdfViewModelProvider.notifier);
// Add listener to update zoom level when controller zoom changes
_viewModel.controller.addListener(_onControllerChanged);
_areas = [ _areas = [
Area( Area(
size: _lastPagesWidth, size: _lastPagesWidth,
@ -270,6 +295,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
@override @override
void dispose() { void dispose() {
_viewModel.controller.removeListener(_onControllerChanged);
_splitController.dispose(); _splitController.dispose();
super.dispose(); super.dispose();
} }
@ -323,14 +349,36 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
onClosePdf: _closePdf, onClosePdf: _closePdf,
onJumpToPage: _jumpToPage, onJumpToPage: _jumpToPage,
onZoomOut: () { onZoomOut: () {
setState(() { if (_viewModel.controller.isReady) {
_zoomLevel = (_zoomLevel - 10).clamp(10, 800); _viewModel.controller.zoomDown();
}); // Update display zoom level after controller zoom
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {
_zoomLevel = (_viewModel.controller.currentZoom *
100)
.round()
.clamp(10, 800);
});
}
});
}
}, },
onZoomIn: () { onZoomIn: () {
setState(() { if (_viewModel.controller.isReady) {
_zoomLevel = (_zoomLevel + 10).clamp(10, 800); _viewModel.controller.zoomUp();
}); // Update display zoom level after controller zoom
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {
_zoomLevel = (_viewModel.controller.currentZoom *
100)
.round()
.clamp(10, 800);
});
}
});
}
}, },
zoomLevel: _zoomLevel, zoomLevel: _zoomLevel,
filePath: widget.currentFile.path, filePath: widget.currentFile.path,

View File

@ -126,6 +126,44 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
onClearActiveOverlay: widget.onClearActiveOverlay, onClearActiveOverlay: widget.onClearActiveOverlay,
onSelectPlaced: widget.onSelectPlaced, onSelectPlaced: widget.onSelectPlaced,
), ),
// Vertical scroll thumb on the right
PdfViewerScrollThumb(
controller: widget.controller,
orientation: ScrollbarOrientation.right,
thumbSize: const Size(40, 25),
thumbBuilder:
(context, thumbSize, pageNumber, controller) => Container(
color: Colors.black.withValues(alpha: 0.7),
child: Center(
child: Text(
pageNumber.toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 12,
),
),
),
),
),
// Horizontal scroll thumb on the bottom
PdfViewerScrollThumb(
controller: widget.controller,
orientation: ScrollbarOrientation.bottom,
thumbSize: const Size(40, 25),
thumbBuilder:
(context, thumbSize, pageNumber, controller) => Container(
color: Colors.black.withValues(alpha: 0.7),
child: Center(
child: Text(
pageNumber.toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 12,
),
),
),
),
),
]; ];
}, },
), ),