0
votes

I'm trying to open a PDF dynamically and not from a static string, so that I can upload multiple pdf's and it opens whichever the user has selected. It instantiates using the FullPDFViewerScreen widget below, and I'd like to be able to pass other PDF's and change the title also subjective to the PDF chosen.

Here is my class for it:

import 'data.dart';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_full_pdf_viewer/full_pdf_viewer_scaffold.dart';
import 'dart:typed_data';

class Detail extends StatelessWidget {
  final Book book;

  Detail(this.book);

  final String _documentPath = 'PDFs/test-en.pdf';

  @override
  Widget build(BuildContext context) {

    Future<String> prepareTestPdf() async {
      final ByteData bytes =
          await DefaultAssetBundle.of(context).load(_documentPath);
      final Uint8List list = bytes.buffer.asUint8List();

      final tempDir = await getTemporaryDirectory();
      final tempDocumentPath = '${tempDir.path}/$_documentPath';

      final file = await File(tempDocumentPath).create(recursive: true);
      file.writeAsBytesSync(list);
      return tempDocumentPath;
    }

    //app bar
    final appBar = AppBar(
      elevation: .5,
      title: Text(book.title),
    );

    ///detail of book image and it's pages
    final topLeft = Column(
      children: <Widget>[
        Padding(
          padding: EdgeInsets.all(16.0),
          child: Hero(
            tag: book.title,
            child: Material(
              elevation: 15.0,
              shadowColor: Colors.yellow.shade900,
              child: Image(
                image: AssetImage(book.image),
                fit: BoxFit.cover,
              ),
            ),
          ),
        ),
        text('${book.pages} pages', color: Colors.black38, size: 12)
      ],
    );

    ///detail top right
    final topRight = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        text(book.title,
            size: 16, isBold: true, padding: EdgeInsets.only(top: 16.0)),
        text(
          'by ${book.writer}',
          color: Colors.black54,
          size: 12,
          padding: EdgeInsets.only(top: 8.0, bottom: 16.0),
        ),
        Row(
          children: <Widget>[
            text(
              book.price,
              isBold: true,
              padding: EdgeInsets.only(right: 8.0),
            ),
          ],
        ),
        SizedBox(height: 32.0),
        Material(
          borderRadius: BorderRadius.circular(20.0),
          shadowColor: Colors.blue.shade200,
          elevation: 5.0,
          child: MaterialButton(
            onPressed: () {
              // We need to prepare the test PDF, and then we can display the PDF.
              prepareTestPdf().then(
                (path) {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => FullPdfViewerScreen(path)),
                  );
                },
              );
            },
            minWidth: 160.0,
            color: Colors.blue,
            child: text('Read Now', color: Colors.white, size: 13),
          ),
        )
      ],
    );

    final topContent = Container(
      color: Theme.of(context).primaryColor,
      padding: EdgeInsets.only(bottom: 16.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Flexible(flex: 2, child: topLeft),
          Flexible(flex: 3, child: topRight),
        ],
      ),
    );

    ///scrolling text description
    final bottomContent = Container(
      height: 220.0,
      child: SingleChildScrollView(
        padding: EdgeInsets.all(16.0),
        child: Text(
          book.description,
          style: TextStyle(fontSize: 13.0, height: 1.5),
        ),
      ),
    );

    return Scaffold(
      appBar: appBar,
      body: Column(
        children: <Widget>[topContent, bottomContent],
      ),
    );
  }

  //create text widget
  text(String data,
          {Color color = Colors.black87,
          num size = 14,
          EdgeInsetsGeometry padding = EdgeInsets.zero,
          bool isBold = false}) =>
      Padding(
        padding: padding,
        child: Text(
          data,
          style: TextStyle(
              color: color,
              fontSize: size.toDouble(),
              fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
        ),
      );
}

class FullPdfViewerScreen extends StatelessWidget {
  final String pdfPath;

  FullPdfViewerScreen(this.pdfPath);

  @override
  Widget build(BuildContext context) {
    return PDFViewerScaffold(
        appBar: AppBar(
          title: Text("Document"),
        ),
        path: pdfPath);
  }
}

main.dart where it generates the route for the detail page. I need to access the books.path that's where the pdf route is mentioned for each book.

 generateRoute(RouteSettings settings) {
    final path = settings.name.split('/');
    final title = path[1];

    Book book = books.firstWhere((it) => it.title == title);
    return MaterialPageRoute(
      settings: settings,
      builder: (context) => Detail(book),
    );
  }
2
Why not pass the documentPath and documentTitle to the Detail widget along with the book? And then pass the documentTitle further on to the FullPdfViewerScreen widget to use it in the AppBar. - Ovidiu
It's unable to get any information from the documentPath and documentTitle. I'm also adding the information from the main.dart where it access the Books class to to segue to the detail page. - MrPool
Sorry but I don't understand your problem. You've just shown code according to which the title is available at the point of navigating to the Detail widget, so I don't see any reason why you couldn't pass the title to the Detail widget. Similarly, the documentPath should be obtained from a mapping between books/titles and paths, and passed to the Detail widget. - Ovidiu

2 Answers

0
votes

Update:

It seems, I misunderstood you question.

You just need to pass title and path as a parameter.

Change:

  final Book book;
  Detail(this.book);
  final String _documentPath = 'PDFs/test-en.pdf';

To:

  final Book book;
  final String documentPath;
  Detail(this.book, this.documentPath);

And you can get Title from book.title variable


If you want to get the pdf file from URL, you can use flutter_downloader widget.

Here is a working example.

You can pass the list of files with their file name and url. Download them using:

    task.taskId = await FlutterDownloader.enqueue(
    url: task.link,
    headers: {"auth": "test_for_sql_encoding"},
    savedDir: _localPath,
    showNotification: true,
    openFileFromNotification: true);

And check if they are completed with:

if(item.task.status == DownloadTaskStatus.complete)

When completed, you can pass _localPath/fileName to FullPdfViewerScreen to open the file. (_localPath is the path you used while downloading the file.

0
votes

You should also pass the path as parameter. Like this;

class Detail extends StatelessWidget {
  final Book book;
  final String documentPath; // <-- Add this line 

  Detail(this.book, this.documentPath); <-- Edit this line 

  @override
  Widget build(BuildContext context) {

    Future<String> prepareTestPdf() async {
      final ByteData bytes =
          await DefaultAssetBundle.of(context).load(documentPath); // Also edit your path
      final Uint8List list = bytes.buffer.asUint8List();

      final tempDir = await getTemporaryDirectory();
      final tempDocumentPath = '${tempDir.path}/$documentPath';

      final file = await File(tempDocumentPath).create(recursive: true);
      file.writeAsBytesSync(list);
      return tempDocumentPath;
    }
...

On your generateRoute, you should do like this;

 generateRoute(RouteSettings settings) {
    final path = settings.name.split('/');
    final title = path[1];

    Book book = books.firstWhere((it) => it.title == title);
    return MaterialPageRoute(
      settings: settings,
      builder: (context) => Detail(book,settings.name), // <-- This is your path as parameter.
    );
  }