Flutterバスケアプリ | 保存済み試合データのPDFエクスポート機能(仮)

保存済みの試合データをPDF形式でエクスポートできる機能(仮)を追加しました。”(仮)”とつけていますが、今回のバージョンは試合名やチーム名を表示しているだけのため実際のランニングスコアは含んでいません。次回以降に含める予定です。

機能の詳細

PDFエクスポート機能は、保存済み試合データの一覧から特定の試合を選択し、その試合データをPDFファイルとして保存するものです。PDFファイルは日本語フォント「NotoSansJP-Regular」を使用しており、試合名、会場、日付、チームIDなどの情報を含みます。


実装手順

1. 必要なライブラリのインストール

まず、pubspec.yaml ファイルに pdf ライブラリとフォントファイルを追加しました。

dependencies:
  flutter:
    sdk: flutter
  pdf: ^3.6.5
  path_provider: ^2.0.11

flutter:
  uses-material-design: true
  assets:
    - assets/fonts/NotoSansJP-Regular.ttf

2. PDFエクスポートの実装

次に、GameDataScreen クラスにPDFエクスポート機能を追加しました。以下が関連するソースコードです。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'game_entry_provider.dart';
import 'score_input_screen.dart';

class GameDataScreen extends StatefulWidget {
  @override
  _GameDataScreenState createState() => _GameDataScreenState();
}

class _GameDataScreenState extends State<GameDataScreen> {
  final GameEntryProvider _gameProvider = GameEntryProvider();
  List<GameEntry> _games = [];
  Set<int> _selectedGameIds = Set<int>();

  @override
  void initState() {
    super.initState();
    _loadGames();
  }

  Future<void> _loadGames() async {
    List<GameEntry> games = await _gameProvider.getAllGames();
    setState(() {
      _games = games;
    });
  }

  Future<void> _deleteGame(int gameId) async {
    await _gameProvider.deleteGame(gameId);
    _loadGames();
  }

  // 日本語フォントを適用したPDF生成
  Future<void> _exportGameToPdf(GameEntry game) async {
    try {
      final pdf = pw.Document();

      // フォントの読み込み
      final fontData =
          await rootBundle.load("assets/fonts/NotoSansJP-Regular.ttf");
      final ttf = pw.Font.ttf(fontData);

      // PDFページを追加
      pdf.addPage(
        pw.Page(
          build: (pw.Context context) => pw.Center(
            child: pw.Column(
              mainAxisAlignment: pw.MainAxisAlignment.center,
              children: [
                pw.Text(
                  '試合名: ${game.name}',
                  style: pw.TextStyle(font: ttf, fontSize: 24),
                ),
                pw.Text('会場: ${game.venue}', style: pw.TextStyle(font: ttf)),
                pw.Text('日付: ${game.date}', style: pw.TextStyle(font: ttf)),
                pw.Text('チームA ID: ${game.teamAId}',
                    style: pw.TextStyle(font: ttf)),
                pw.Text('チームB ID: ${game.teamBId}',
                    style: pw.TextStyle(font: ttf)),
              ],
            ),
          ),
        ),
      );

      // ドキュメントディレクトリにPDFを保存
      final directory = await getApplicationDocumentsDirectory();
      final file = File('${directory.path}/game_${game.id}.pdf');
      await file.writeAsBytes(await pdf.save());

      // 保存成功メッセージ
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('PDFが ${file.path} に保存されました')),
      );
    } catch (error) {
      // エラーメッセージを表示
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('エラーが発生しました: $error')),
      );
    }
  }

  // その他のコード...

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('保存済みの試合データ'),
        actions: [
          IconButton(
            icon: Icon(Icons.delete),
            onPressed: _selectedGameIds.isNotEmpty
                ? () => _showDeleteConfirmationDialog(null)
                : null,
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: _games.length,
        itemBuilder: (context, index) {
          final game = _games[index];
          final isSelected = _selectedGameIds.contains(game.id);

          return ListTile(
            leading: Checkbox(
              value: isSelected,
              onChanged: (bool? value) {
                setState(() {
                  if (value == true) {
                    _selectedGameIds.add(game.id!);
                  } else {
                    _selectedGameIds.remove(game.id);
                  }
                });
              },
            ),
            title: Text(game.name),
            subtitle: Text('会場: ${game.venue} - 日付: ${game.date}'),
            trailing: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                IconButton(
                  icon: Icon(Icons.picture_as_pdf),
                  onPressed: () => _exportGameToPdf(game),
                ),
                IconButton(
                  icon: Icon(Icons.edit),
                  onPressed: () => _showEditGameDialog(game),
                ),
                IconButton(
                  icon: Icon(Icons.delete),
                  onPressed: () => _showDeleteConfirmationDialog(game.id),
                ),
              ],
            ),
            onTap: () => _showLoadGameDialog(game),
          );
        },
      ),
    );
  }
}

3. 実装後の動作確認

上記のコードを実装した後、保存済み試合データの一覧画面に表示されるPDFアイコンをクリックすると、指定したフォルダに試合データがPDFとして保存されます。

スクリーンショット

関連記事

コメント

タイトルとURLをコピーしました