pdf_viewer_pro 0.0.1 copy "pdf_viewer_pro: ^0.0.1" to clipboard
pdf_viewer_pro: ^0.0.1 copied to clipboard

A full-featured Flutter PDF viewer built on PDFium (pdfrx). Includes annotations, bookmarks, full-text search, thumbnails, table of contents, auto-scroll, dark/light themes, DRM screenshot protection, [...]

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart' hide Rx, RxBool, RxInt, RxDouble, RxString, RxList, RxMap, Obx, Worker;
import 'package:get_storage/get_storage.dart';
import 'package:file_picker/file_picker.dart';
import 'package:pdf_viewer_pro/pdf_viewer_pro.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await GetStorage.init();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'PDF Viewer Pro Example',
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
        brightness: Brightness.dark,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Theme configuration
  Color _primaryColor = Colors.blue;
  bool _useDarkMode = false;
  final _darkMode = RxBool(false);

  // Feature toggles
  bool _enableBookmarks = true;
  bool _enableAnnotations = true;
  bool _enableSearch = true;
  bool _enableThumbnails = true;
  bool _enableAutoScroll = true;
  bool _enableScreenProtection = false;
  bool _enableSettings = true;
  bool _enableFullscreen = true;

  // Theme customization
  Color _lightBg = Colors.white;
  Color _darkBg = const Color(0xFF121212);
  double _cardRadius = 12.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('PDF Viewer Pro Example'),
        actions: [
          IconButton(
            icon: Icon(_useDarkMode ? Icons.light_mode : Icons.dark_mode),
            onPressed: () {
              setState(() {
                _useDarkMode = !_useDarkMode;
                _darkMode.value = _useDarkMode;
              });
            },
          ),
        ],
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // === Open PDF Button ===
            FilledButton.icon(
              onPressed: _openPdfFromFile,
              icon: const Icon(Icons.file_open),
              label: const Text('Open PDF from Device'),
            ),
            const SizedBox(height: 8),
            OutlinedButton.icon(
              onPressed: _openPdfFromUrl,
              icon: const Icon(Icons.link),
              label: const Text('Open PDF from URL'),
            ),
            const SizedBox(height: 8),
            OutlinedButton.icon(
              onPressed: _openMinimalViewer,
              icon: const Icon(Icons.remove_red_eye),
              label: const Text('Open Minimal Viewer (No Extras)'),
            ),
            const SizedBox(height: 8),
            OutlinedButton.icon(
              onPressed: _openSimplePdfViewer,
              icon: const Icon(Icons.picture_as_pdf),
              label: const Text('Open Simple PDF Viewer'),
            ),

            const SizedBox(height: 24),
            const Divider(),

            // === Theme Configuration ===
            const Text(
              'Theme Configuration',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 12),

            // Primary color picker
            const Text('Primary Color'),
            const SizedBox(height: 8),
            Wrap(
              spacing: 8,
              children: [
                Colors.blue,
                Colors.red,
                Colors.green,
                Colors.purple,
                Colors.orange,
                Colors.teal,
                Colors.pink,
                Colors.indigo,
              ]
                  .map((color) => GestureDetector(
                        onTap: () => setState(() => _primaryColor = color),
                        child: CircleAvatar(
                          radius: 18,
                          backgroundColor: color,
                          child: _primaryColor == color
                              ? const Icon(Icons.check,
                                  color: Colors.white, size: 18)
                              : null,
                        ),
                      ))
                  .toList(),
            ),
            const SizedBox(height: 12),

            // Card border radius
            Row(
              children: [
                const Text('Card Border Radius: '),
                Expanded(
                  child: Slider(
                    value: _cardRadius,
                    min: 0,
                    max: 24,
                    divisions: 12,
                    label: _cardRadius.round().toString(),
                    onChanged: (v) => setState(() => _cardRadius = v),
                  ),
                ),
              ],
            ),

            // Light background color
            const Text('Light Background'),
            const SizedBox(height: 4),
            Wrap(
              spacing: 8,
              children: [
                Colors.white,
                const Color(0xFFF5F5F5),
                const Color(0xFFFFF8E1),
                const Color(0xFFE8F5E9),
              ]
                  .map((color) => GestureDetector(
                        onTap: () => setState(() => _lightBg = color),
                        child: Container(
                          width: 36,
                          height: 36,
                          decoration: BoxDecoration(
                            color: color,
                            border: Border.all(
                              color: _lightBg == color
                                  ? Colors.blue
                                  : Colors.grey.shade300,
                              width: _lightBg == color ? 2 : 1,
                            ),
                            borderRadius: BorderRadius.circular(6),
                          ),
                        ),
                      ))
                  .toList(),
            ),

            // Dark background color
            const SizedBox(height: 8),
            const Text('Dark Background'),
            const SizedBox(height: 4),
            Wrap(
              spacing: 8,
              children: [
                const Color(0xFF121212),
                const Color(0xFF1a1a1a),
                const Color(0xFF212121),
                const Color(0xFF263238),
              ]
                  .map((color) => GestureDetector(
                        onTap: () => setState(() => _darkBg = color),
                        child: Container(
                          width: 36,
                          height: 36,
                          decoration: BoxDecoration(
                            color: color,
                            border: Border.all(
                              color: _darkBg == color
                                  ? Colors.blue
                                  : Colors.grey.shade600,
                              width: _darkBg == color ? 2 : 1,
                            ),
                            borderRadius: BorderRadius.circular(6),
                          ),
                        ),
                      ))
                  .toList(),
            ),

            const SizedBox(height: 24),
            const Divider(),

            // === Feature Toggles ===
            const Text(
              'Feature Toggles',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),

            _featureSwitch('Bookmarks', _enableBookmarks,
                (v) => setState(() => _enableBookmarks = v)),
            _featureSwitch('Annotations', _enableAnnotations,
                (v) => setState(() => _enableAnnotations = v)),
            _featureSwitch('Search', _enableSearch,
                (v) => setState(() => _enableSearch = v)),
            _featureSwitch('Thumbnails', _enableThumbnails,
                (v) => setState(() => _enableThumbnails = v)),
            _featureSwitch('Auto-scroll', _enableAutoScroll,
                (v) => setState(() => _enableAutoScroll = v)),
            _featureSwitch('Screen Protection', _enableScreenProtection,
                (v) => setState(() => _enableScreenProtection = v)),
            _featureSwitch('Settings Panel', _enableSettings,
                (v) => setState(() => _enableSettings = v)),
            _featureSwitch('Fullscreen', _enableFullscreen,
                (v) => setState(() => _enableFullscreen = v)),
          ],
        ),
      ),
    );
  }

  Widget _featureSwitch(
      String label, bool value, ValueChanged<bool> onChanged) {
    return SwitchListTile(
      title: Text(label),
      value: value,
      dense: true,
      contentPadding: EdgeInsets.zero,
      onChanged: onChanged,
    );
  }

  PdfViewerThemeConfig _buildThemeConfig() {
    return PdfViewerThemeConfig(
      primaryColor: _primaryColor,
      lightBackgroundColor: _lightBg,
      darkBackgroundColor: _darkBg,
      cardBorderRadius: _cardRadius,
      bookmarkColor: _primaryColor,
      sliderActiveColor: _primaryColor,
      loadingIndicatorColor: _primaryColor,
    );
  }

  PdfViewerFeatureConfig _buildFeatureConfig() {
    return PdfViewerFeatureConfig(
      enableBookmarks: _enableBookmarks,
      enableAnnotations: _enableAnnotations,
      enableSearch: _enableSearch,
      enableThumbnails: _enableThumbnails,
      enableAutoScroll: _enableAutoScroll,
      enableScreenProtection: _enableScreenProtection,
      enableSettings: _enableSettings,
      enableFullscreen: _enableFullscreen,
    );
  }

  PdfViewerServiceConfig _buildServiceConfig() {
    return PdfViewerServiceConfig(
      onMessage: (message, type) {
        final color = type == ViewerMessageType.error
            ? Colors.red
            : type == ViewerMessageType.warning
                ? Colors.orange
                : Colors.green;
        Get.snackbar(
          type.name.toUpperCase(),
          message,
          snackPosition: SnackPosition.BOTTOM,
          backgroundColor: color.withValues(alpha: 0.9),
          colorText: Colors.white,
          duration: const Duration(seconds: 2),
        );
      },
    );
  }

  Future<void> _openPdfFromFile() async {
    final result = await FilePicker.platform.pickFiles(
      type: FileType.custom,
      allowedExtensions: ['pdf'],
    );

    if (result != null && result.files.single.path != null) {
      Get.to(() => PdfViewerScreen(
            filePath: result.files.single.path!,
            title: result.files.single.name,
            serviceConfig: _buildServiceConfig(),
            themeConfig: _buildThemeConfig(),
            featureConfig: _buildFeatureConfig(),
            externalDarkMode: _darkMode,
          ));
    }
  }

  void _openPdfFromUrl() {
    // Open with a sample public PDF URL
    Get.to(() => PdfViewerScreen(
          filePath: '',
          fileUrl:
              'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf',
          title: 'Sample PDF from URL',
          serviceConfig: _buildServiceConfig(),
          themeConfig: _buildThemeConfig(),
          featureConfig: _buildFeatureConfig(),
          externalDarkMode: _darkMode,
        ));
  }

  Future<void> _openMinimalViewer() async {
    final result = await FilePicker.platform.pickFiles(
      type: FileType.custom,
      allowedExtensions: ['pdf'],
    );

    if (result != null && result.files.single.path != null) {
      Get.to(() => PdfViewerScreen(
            filePath: result.files.single.path!,
            title: result.files.single.name,
            featureConfig: PdfViewerFeatureConfig.minimal,
            themeConfig: PdfViewerThemeConfig(
              primaryColor: Colors.grey,
              lightBackgroundColor: const Color(0xFFFAFAFA),
              darkBackgroundColor: const Color(0xFF1E1E1E),
            ),
          ));
    }
  }

  Future<void> _openSimplePdfViewer() async {
    final result = await FilePicker.platform.pickFiles(
      type: FileType.custom,
      allowedExtensions: ['pdf'],
    );

    if (result != null && result.files.single.path != null) {
      Get.to(() => Scaffold(
            appBar: AppBar(title: Text(result.files.single.name)),
            body: SimplePdfViewer.file(result.files.single.path!),
          ));
    }
  }
}
1
likes
130
points
118
downloads

Documentation

API reference

Publisher

verified publishercodingfrontend.in

Weekly Downloads

A full-featured Flutter PDF viewer built on PDFium (pdfrx). Includes annotations, bookmarks, full-text search, thumbnails, table of contents, auto-scroll, dark/light themes, DRM screenshot protection, and optional server-sync callbacks.

Homepage
Repository (GitHub)
View/report issues

Topics

#pdf #viewer #drm #annotations #flutter

License

MIT (license)

Dependencies

flutter, http, path_provider, pdfrx, screen_protector

More

Packages that depend on pdf_viewer_pro