Lento con forza

大学生気分のIT系エンジニアが色々書いてく何か。ブログ名決めました。

ChatGPTでアプリを作る Part4 いよいよアプリの機能を作っていくぜ

ChatGPTでアプリを作ろうとしています、id:kouki_dan です。

前回のPart3では、ログイン、ログアウトの画面を作ってきました。それも、ChatGPTが書いてくれたコードをコピーしてペーストしていくだけでです。

kouki.hatenadiary.com

今回は、順番的にいうと、やっと機能を作っていくことになるでしょう。

Part1で決めたように、このアプリは、冷凍庫の中身を管理してくれるアプリで、名前は「FreezStock」です。今回もChatGPTの赴くままに機能を実装していきましょう!

今回はYouTubeでライブをしながらやってみました!

www.youtube.com

ありがとうございました。次に進みたいと思います。 どういたしまして。次のステップに進む準備ができているようです。アプリ開発の次のステップは、冷凍庫の中身の一覧画面、追加画面、編集画面などを作成することです。これらの画面を実装することで、アプリの基本的な機能が完成します。  もし、途中で質問や助けが必要な場合は、遠慮なくお聞きください。開発がスムーズに進むことを願っています!

前回の延長線ということで、お礼を言った後に次に進む意思表示をしました。すると、次にやらなければいけないことを教えてもらえました。

Part1では、次にやるべきことは冷凍庫一覧画面のはずなのですが、ChatGPTさんは完全に忘れていますね。冷凍庫一覧画面は正直いらないと思ってたので、このまま先に進みます!

次にやるべきことを教えてください  次にやるべきことは、冷凍庫の中身を表示・管理するための画面と機能を実装することです。以下の手順を参考にしてください。  データモデルの作成: 冷凍庫の中身を表すデータモデル(クラス)を作成します。このデータモデルには、食品名、数量、賞味期限、追加日時などの情報が含まれます。  Firestoreとの連携: Firestoreを使用して、冷凍庫の中身のデータを保存・取得する処理を実装します。  冷凍庫の中身一覧画面: 冷凍庫の中身を一覧表示する画面を作成します。Firestoreから取得したデータをリスト表示し、リストアイテムをタップすることで詳細画面や編集画面に遷移できるようにします。  冷凍庫の中身追加画面: 冷凍庫に新たな食品を追加するための画面を作成します。食品名、数量、賞味期限、追加日時などの情報を入力し、Firestoreにデータを保存できるようにします。  冷凍庫の中身詳細画面: 選択した食品の詳細情報を表示する画面を作成します。編集ボタンを押すことで編集画面に遷移できるようにします。  冷凍庫の中身編集画面: 選択した食品の情報を編集する画面を作成します。編集後、Firestoreのデータを更新できるようにします。  これらのステップを終えると、冷凍庫の中身を管理できる基本的なアプリが完成します。途中で質問がある場合は、遠慮なくお聞きください。開発がスムーズに進むことを願っています!

ということで、次にやるべきことを再度聞いてみると、詳細化してくれました。今回は、これを1つ1つ実装していくことになりそうですね。

データモデルを作成してください データモデルを作成するために、まず新しいファイルfrozen_item.dartを作成し、以下のような内容で記述します。

class FrozenItem {
  final String id;
  final String name;
  final int quantity;
  final DateTime expirationDate;
  final DateTime addedDate;

  FrozenItem({
    required this.id,
    required this.name,
    required this.quantity,
    required this.expirationDate,
    required this.addedDate,
  });

  // JSONデータをFrozenItemオブジェクトに変換するファクトリメソッド
  factory FrozenItem.fromJson(Map<String, dynamic> json) {
    return FrozenItem(
      id: json['id'],
      name: json['name'],
      quantity: json['quantity'],
      expirationDate: DateTime.fromMillisecondsSinceEpoch(json['expirationDate']),
      addedDate: DateTime.fromMillisecondsSinceEpoch(json['addedDate']),
    );
  }

  // FrozenItemオブジェクトをJSONデータに変換するメソッド
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'quantity': quantity,
      'expirationDate': expirationDate.millisecondsSinceEpoch,
      'addedDate': addedDate.millisecondsSinceEpoch,
    };
  }
}

このクラスは、冷凍庫の中身を表すデータモデルです。食品名、数量、賞味期限、追加日時などの情報を保持しています。また、JSONデータとFrozenItemオブジェクトの相互変換を行うためのメソッドが実装されています。これにより、Firestoreとのデータのやり取りが容易になります。  このデータモデルを使用して、アプリの各画面で冷凍庫の中身を表示・編集・追加する処理を実装していきます。

なんと、一発でそれっぽいデータクラスを作ってくれました。これをそのままコピペしていきます。次に、2つ目のFirestoreとの連携を聞いてみます。

Firestoreとの連携を作成してください まず、Firestoreとの連携に必要なパッケージを追加します。pubspec.yamlに以下のパッケージを追加してください。  yaml Copy code dependencies:   cloud_firestore: ^3.1.7 次に、firestore_service.dartという新しいファイルを作成し、以下のコードを追加します。このコードでは、Firestoreとの連携を行うための基本的なCRUD操作が実装されています。

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezstock/frozen_item.dart';

class FirestoreService {
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;
  final String _collectionName = 'frozen_items';

  // 冷凍庫の中身を取得するメソッド
  Stream<List<FrozenItem>> getFrozenItems() {
    return _firestore
        .collection(_collectionName)
        .snapshots()
        .map((snapshot) => snapshot.docs
            .map((doc) => FrozenItem.fromJson({...doc.data(), 'id': doc.id}))
            .toList());
  }

  // 冷凍庫に新しい食品を追加するメソッド
  Future<void> addFrozenItem(FrozenItem item) {
    return _firestore.collection(_collectionName).add(item.toJson());
  }

  // 選択した食品の情報を更新するメソッド
  Future<void> updateFrozenItem(FrozenItem item) {
    return _firestore
        .collection(_collectionName)
        .doc(item.id)
        .update(item.toJson());
  }

  // 選択した食品を削除するメソッド
  Future<void> deleteFrozenItem(String itemId) {
    return _firestore.collection(_collectionName).doc(itemId).delete();
  }
}

すごい、それっぽいデータを管理するクラスが勝手に作成されました。続いて冷凍庫の中身一覧画面を要求してみましょう。

冷凍庫の中身一覧画面を作成してください まず、main_screen.dartという新しいファイルを作成し、以下のコードを追加してください。このコードでは、MainScreenウィジェットが作成され、FirestoreServiceを利用して冷凍庫の中身の一覧を取得し、リストビューで表示しています。

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezstock/firestore_service.dart';
import 'package:freezstock/frozen_item.dart';

class MainScreen extends StatefulWidget {
  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  final FirestoreService _firestoreService = FirestoreService();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('冷凍庫の中身'),
      ),
      body: StreamBuilder<List<FrozenItem>>(
        stream: _firestoreService.getFrozenItems(),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return Center(child: Text('エラーが発生しました'));
          }

          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          }

          final items = snapshot.data;
          if (items == null || items.isEmpty) {
            return Center(child: Text('冷凍庫にアイテムがありません'));
          }

          return ListView.builder(
            itemCount: items.length,
            itemBuilder: (context, index) {
              final item = items[index];
              return ListTile(
                title: Text(item.name),
                subtitle: Text('${item.quantity}個 - 期限: ${item.expirationDate}'),
                onTap: () {
                  // アイテムの詳細画面に遷移する処理をここに追加する
                },
              );
            },
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // アイテム追加画面に遷移する処理をここに追加する
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

どんどん勝手に画面が出来上がっていきます。この調子で、冷凍庫の中身追加画面と冷凍庫の中身詳細画面、冷凍庫の中身編集画面も作成してくれました。

画面はどんどん作ってくれたのですが、いざ実行しようとするとエラーになります。エラーも直してもらいましょう。 add_item_screenで以下のエラーが出ます The named parameter &#x27;id&#x27; is required, but there&#x27;s no corresponding argument. Try adding the required argument.dartmissing_required_argument AddItemScreenからEditItemScreenへの遷移時に、idパラメータが必要ですが、渡していないためエラーが発生しています。AddItemScreen内で、新しいアイテムを作成するときにはIDを渡さないように修正して、エラーを解決しましょう。  EditItemScreenのコンストラクタで、idパラメータをオプショナルにします。また、_EditItemScreenStateでitemの初期化を修正します。  edit_item_screen.dart

import 'package:flutter/material.dart';
import 'package:freezstock/frozen_item.dart';

class EditItemScreen extends StatefulWidget {
  final FrozenItem item;
  final String? id;

  EditItemScreen({required this.item, this.id});

  @override
  _EditItemScreenState createState() => _EditItemScreenState();
}

class _EditItemScreenState extends State<EditItemScreen> {
  final _formKey = GlobalKey<FormState>();
  late FrozenItem item;

  @override
  void initState() {
    super.initState();
    item = widget.item;
  }

  // 以下のコードは変更なし
  ...
}

エラーメッセージだけで、的確に、コンパイルエラーが修正されていきます。

忘れていそうなところは、適宜実装を教えてあげると、やらなければいけないことを教えてくれます。

IconButton(
  icon: Icon(Icons.save),
  onPressed: () async {
    if (_formKey.currentState!.validate()) {
      await _firestoreService.updateFrozenItem(
        FrozenItem(
          id: widget.item.id,
          name: _nameController.text,
          quantity: int.parse(_quantityController.text),
          expirationDate: DateTime.parse(_expirationDateController.text),
          addedDate: widget.item.addedDate,
        ),
      );
      Navigator.pop(context);
    }
  },
),

最後に、Firestoreのルールがなくエラーが出てしまうのを解消します。(FirestoreのエラーだということをChatGPTに気づいてもらおうと頑張ったのですがうまくできなかったので、代わりに僕がデバッグしました)

アプリを起動しましたが、Firestoreのルールがなくエラーになるようです。本番用のルールを作成してください The previous model used in this conversation is unavailable. We&#x27;ve switched you to the latest default model Firebase ConsoleからFirestoreの画面に移動し、ルールタブをクリックします。  以下のルールを記述し、「公開するに変更」ボタンをクリックして、ルールを公開してください。

さて、これで動く状態になりましたね!ざっと動かすとこんな感じです!!

ただ、このアプリにはいくつか問題がありますね。せっかくログインしているのに、全員でデータを共通にしていたりします。他にも、日付はDatePickerを使うことだったり、色々改善点は見つかりそうです。

でもそれには一旦目を瞑って、次に作らなければいけない機能をChatGPTに聞いてみると・・・?

どうやら、ユーザーテストらしい・・・。誰かユーザーテストに付き合ってくれる人はいらっしゃいませんか!?

Part1によると、次は期限切れリマインダーだったんですけどね〜〜

今回ChatGPTに書いてもらったコードはこれです!

github.com