屌炸天!國外同行這樣用Chat GPT提高Flutter開發的效率!

語言: CN / TW / HK

theme: v-green highlight:


本文正在參加「金石計劃」

原文鏈接:https://medium.com/flutter-community/how-a-flutter-developer-can-use-chat-gpt-to-improve-productivity-ef834e03a87c,翻譯時根據需要做了刪減。

前言

作為一個Flutter的開發者,我們肯定希望能夠尋求手段來改進開發效率,讓開發工作更順暢。現在,Chat GPT能夠幫我們達到這個目的了。本篇,我們將向你展示如何使用Chat GPT提高Flutter開發者的效率。

Chat GPT可以在哪些方面幫助Flutter開發者?

這是我們整理的Chat GPT最適合幫助Flutter 開發者的7個點:

  1. 生成代碼

可以利用Chat GPT自動生成你需要的代碼來提高效率。Chat GPT可以基於你已有的代碼庫進行訓練來生成特定的代碼片段。例如,如果你需要創建一個新的widget,你可以給Chat GPT提供對應的要求,然後它會幫你生成需要的代碼。這可以幫你節省很多實現不同原型的時間。

  1. 測試和調試

Chat GPT可以測試和調試你的代碼。可以在Chat GPT中輸入特定的測試用例,然後它會生成對應的輸出結果。這可以讓你快速定位和修復代碼的bug。此外,Chat GPT還可以生成一些你想不到的邊界測試用例,使得你的代碼更加健壯可靠。

  1. 給代碼加註釋

Chat GPT可以給Flutter代碼增加註釋,使得開發者可以更容易理解和解釋複雜的代碼結構和概念。

  1. 解釋代碼

Chat GPT可以為Flutter或其他程序代碼生成解釋説明。通過給Chat GPT提供一些描述代碼的自然語義語料,模型可以給非技術人員生成可理解的代碼説明。當然,效果的前提取決於提供的語料和提示語,以及代碼自身的複雜程度。

  1. 生成文檔

文檔對於軟件開發來説非常重要,但是編寫文檔非常耗時。通過Chat GPT,可以為你的代碼庫生成文檔。例如,你可以給Chat GPT提供一個特定的函數或類,然後它會給出這個函數的用途説明以及如何使用這個函數,這將節省你的時間並且讓你的代碼庫有比較好的文檔説明。

  1. 給界面開發者提供示例文本

作為Flutter開發者,你經常需要給App創建UI界面。通過Chat GPT,可以給UI界面生成所需要的示例文本。這可以節省你的時間並且幫助你快速完成UI界面。例如,你設計一個即時聊天App,就可以用Chat GPT生成示例的聊天對話信息。

  1. 創建聊天機器人

你可能需要給你的應用增加一個聊天機器人,有了Chat GPT,你就可以訓練他像人那樣響應用户的輸入,這可以提高用户體驗和自動完成一些客服工作。

Chat GPT是代碼生成的最佳工具嗎

需要説明的是,Chat GPT是基於大量自然語言文本進行訓練的,主要是應對自然語言的輸入。雖然它可以產生Flutter或其他程序的代碼及解釋,但是它並不是專門設計做代碼生成任務的。專門用於代碼生成的工具有GPT-Code,Codex以及Open AI的DALL-E。因此,我們需要了解,Chat GPT生成的代碼無法保障高質量,也不會考慮性能優化。此外,對AI模型生成的代碼進行完備的測試和審查十分重要,這樣才能夠保障滿足需求和沒有安全隱患。

應用實例

現在我們來讓Chat GPT幫我們乾點Flutter的活,我們將通過6個場景來看看Chat GPT有多“能幹”。

  1. 編寫一個簡單的數學函數

    Flutter 開發者:你能使用Dart寫一個函數嗎?這個函數接收一個整數參數,然後返回一個介於0和這個整數之間的隨機整數。

    Chat GPT:沒問題!我可以利用dart:math庫編寫一個函數來產生一個0到給定整數的隨機整數。下面是示例,這個函數接收一個名稱為n的整數參數,然後返回一個0到n-1的隨機整數。

```dart import 'dart:math';

int generateRandomNumber(int n) { Random random = Random(); return random.nextInt(n); } ```

Chat GPT:下面是這個函數的使用示例:

dart void main() { print(generateRandomNumber(10)); // Example output: 6 print(generateRandomNumber(100)); // Example output: 56 print(generateRandomNumber(5)); // Example output: 2 }

Chat GPT: 注意Random.nextInt() 方法返回的值是從0(含0)到給定的值(不包含),因此我們不需要像Python那樣把n-1。

  1. 編寫一個從firestrore讀取數據的函數

    Flutter 開發者:你能編寫一個從firestore中讀取document中國家字段為“UK”的所有銷量數據的Flutter函數嗎。在每個document記錄中有一個字段叫做“amountSold”,請計算所有國家字段為“UK”的總的“amountSold”,然後返回這個計算結果。

    Chat GPT:好的。我可以完成這個函數的編寫。下面是使用cloud_firestore插件實現與FireStore交互的示例函數:

```dart import 'package:cloud_firestore/cloud_firestore.dart';

Future calculateTotalSalesInUK() async { double totalSalesInUK = 0; QuerySnapshot querySnapshot = await FirebaseFirestore.instance .collection('sales') .where('country', isEqualTo: 'UK') .get(); querySnapshot.docs.forEach((document) { totalSalesInUK += document.data()['amountSold']; }); return totalSalesInUK; } ```

Chat GPT: 下面是在Flutter App裏使用這個方法的示例:

dart double ukSales = await calculateTotalSalesInUK(); print('Total sales in UK: $ukSales');

Chat GPT: 注意這是個異步方法,因此在獲得總的銷售數量前需要等待。此外,querySnapshot.docs屬性是所有滿足查詢條件的文檔列表,這裏使用了forEach方法對每個文檔進行迭代來計算總的銷量數值。最終,我們將銷量作為double類型返回。

  1. 編寫一個firebase雲原生函數

    Flutter開發者: 早上好! 請編寫一個名稱為“userRegisration”的firebase雲原生函數。這個函數在firestore中的“customers”集合新增一條文檔時觸發。每個文檔都有一個對應用户電子郵箱的“email”字段,以及一個“name”字段和一個“phone”字段。一旦這個文檔創建的時候,這個函數就會使用用户的電子郵箱在“firebase auth”裏註冊一個賬户。請設置一個隨機的密碼。然後,這個函數必須複製firestore的這個文檔作為用户集合中的新文檔。請將這個文檔的名稱命名為firebase的用户id(uid)。最後,請利用原文檔的信息來填充剛剛創建的用户的屬性。例如設置授權的“displayName”作為用户的“name”字段值,以及設置用户的電話作為字段“phone”的值。

    Chat GPT: 沒問題,下面是你需要的雲原生函數:

```dart const functions = require('firebase-functions'); const admin = require('firebase-admin');

admin.initializeApp();

const firestore = admin.firestore(); const auth = admin.auth();

exports.userRegistration = functions.firestore .document('customers/{customerId}') .onCreate(async (snap, context) => { const data = snap.data(); const email = data.email; const name = data.name; const phone = data.phone;

    // Create a random password for the new user
    const password = Math.random().toString(36).slice(-8);

    // Create a new Firebase Auth user with the provided email and password
    const user = await auth.createUser({
        email: email,
        password: password
    });

    // Set the Firebase Auth display name to the name field in the document
    await auth.updateUser(user.uid, {
        displayName: name
    });

    // Create a new document in the users collection with the same data as the original document
    await firestore.collection('users').doc(user.uid).set({
        name: name,
        phone: phone
    });

    console.log(`New user with email ${email} and UID ${user.uid} has been created.`);

    return null;
});

```

Chat GPT:這個函數監聽Firestore中客户集合的創建行為。一旦一個新的客户文檔創建了,它會從文檔中獲取電子郵箱、姓名和電話等數據。然後,它為新的用户生成了一個隨機密碼,並使用電子郵箱和密碼創建了一個新的Firebase Auth用户。 接下來,它將Firebase Auth的“displayName”設置為用户的“name”字段的值,之後使用了原文檔相同的姓名和電話字段在用户集合中創建了一個新的文檔。 最後,它在控制點打印了一條新用户被創建的消息,並返回null表示函數已經結束。

Flutter 開發者: 可以增加捕獲異常以及在控制枱打印異常的代碼嗎?

Chat GPT: 沒問題! 下面是增加了異常處理後的代碼:

```dart exports.userRegistration = functions.firestore .document("auth_users/{customerId}") .onCreate(async (snap, context) =>{ const data = snap.data(); const email = data.email; const name = data.name; const surname = data.surname; const displayName = name + ' ' + surname; const phone = data.phone; const address = data.address;

  try {
      // Create a random password for the new user
      const password = Math.random().toString(36).slice(-8);

      // Create a new Firebase Auth user with the provided email and password
      const user = await auth.createUser({
          email: email,
          password: password,
        });

      // Set the Firebase Auth display name to the name field in the document
      await auth.updateUser(user.uid, {
          displayName: name,
          phone: phone,
        });

      // Create a new document in the users collection with the same data as the original document
      await firestore.collection("users").doc(user.uid).set({
          email: email,
          name: name,
          surname: surname,
          displayName: displayName,
          phone: phone,
          address: address,
        });

      console.log(`New user with email ${email} and UID ${user.uid} has been created.`);
    } catch (error) {
      console.error(`Error creating user with email ${email}:`, error);
    }

  return null;
});

```

Chat GPT: 我們給創建新的Firebase Auth用户和創建新的用户集合文檔這部分代碼增加了try-catch塊。如果這個過程中出現了錯誤,將會捕獲這個錯誤並且在控制枱打印出來包含用户電子郵箱的錯誤信息。這會幫助你確認和解決用户註冊過程中可能發生的問題。

  1. 解釋代碼

    Flutter 開發者: 你能幫我解釋一下這個代碼嗎:https://github.com/appstree-io/flutter_chating_demo_app/blob/main/lib/service/firebase_service.dart

    Chat GPT: 這是一個使用Firebase作為後端的簡單的聊天應用示例GitHub倉庫代碼。其中 firebase_service.dart 文件負責處理Flutter App與Firebase後端的通信。 下面是這個代碼的簡要説明: FirebaseService類:這是firebase_service.dart文件的主類。它包含了與Firebase交互的方法,例如創建新用户,獲取一個用户的所有聊天會話,發送消息等等。 FirebaseFirestore類:這是Firebase SDK為Flutter提供的類,提供了一個與Firestore數據庫交互的接口。FirebaseService類利用這個類與數據庫進行交互。 UserModel類:這是代表聊天應用用户的一個簡單的類,包括了用户ID、姓名、電子郵箱和頭像等信息。 ChatModel類:這是代表聊天應用聊天會話的一個簡單的類,包括了參與聊天的用户ID,最後發送的消息以及發送消息的時間戳。 MessageModel類:這是代表聊天應用消息的一個簡單的類,包括了發送消息的用户ID,消息文本和消息的時間戳。 createUser方法:這個方法用於在Firebase裏創建一個新用户。它接收UserModel對象作為輸入,然後使用FirebaseFirestore類將用户添加到數據庫。 getChats方法:這個方法獲取用户的所有聊天會話。它使用用户ID作為輸入,然後使用FirebaseFirestore類查詢這個用户ID參與的所有聊天會話。 sendMessage方法:這個方法用於在聊天應用中發送消息。它使用MessageModel對象作為輸入,然後使用FirebaseFirestore類往數據庫裏添加一條消息。 總的來説,firebase_service.dart給Flutter App提供了一個與Firebase簡單通信的接口,並實現了一個簡單的聊天功能。

Flutter 開發者:PlatformExceptionFirebaseAuthException 有什麼區別?

Chat GPT:PlatformExceptionFirebaseAuthException 都代表了Flutter框架中使用Firebase授權認證的發生的錯誤. 二者主要的差別在於設計他們的目的和他們代表的錯誤類型: PlatformException: 這個異常是一個通用型的異常,用來表示發生了在Firebase中沒有定義的錯誤。它是Flutter框架的一部分,典型的情況就是一個平台錯誤發生時拋出。例如,與設備的連接或存儲的連接發生的錯誤 PlatformException 可以被任何與平台功能交互的插件或pacakge拋出。 FirebaseAuthException: 這是一個在於Firebase授權認證交互式發生的特定錯誤。當Firebase的授權認證服務出現錯誤時就會拋出FirebaseAuthException 錯誤,例如無效憑證、用户不存在或用户賬户被禁用。 FirebaseAuthExceptionfirebase_auth的一部分,在 Firebase 授權認證模塊定義。 總的來説,PlatformException是一個發生任何平台類型的錯誤時拋出,而FirebaseAuthException則是Firebase 授權認證的一個具體的錯誤。如果是通過Firebase來做授權認證,那麼應該使用FirebaseAuthException。對於平台類型的錯誤,應該使用PlatformException

  1. 修復錯誤

    Flutter 開發者: 我有如下的Widget:

dart GestureDetector( onTap: () async { myLocalNotifications.cancelNotification(context, reminder.id).then((value) { print('ddd'); printNotification(); }); },

Flutter Developer: 我在其他類中也有這樣的一個方法:

dart Future<void> cancelNotification(context, int notificationId) async { showDialog( context: context, builder: (BuildContext context) { return CustomAlertYesOrNo( alertTitle: 'Confirmation', alertText: 'Do you want to delete this reminder?', onConfirmed: () async { await flutterLocalNotificationsPlugin?.cancel(notificationId).then((value) { print('xxx'); Navigator.pop(context); }); } ); }, ); }

Flutter Developer: 點擊後,這個函數執行正常,我也看到打印了“xxx”。然後,“ddd”並沒有打印,為什麼?我怎麼樣才能讓這個代碼能夠執行?

Chat GPT: 為什麼“ddd”沒有打印的原因是以為它在cancelNotification()方法的.then()回調裏面。很可能是因為某些原因導致這個then()回調沒有執行。 為了調試這個問題,你可以嘗試在cancelNotification()函數增加一個錯誤補償的代碼,看看是不是有錯誤拋出,例如像下面這樣。如果沒有拋出錯誤,你可以在CustomAlertYesOrNo組件里加一下打印語句,看看是否正常顯示以及關閉。

dart await flutterLocalNotificationsPlugin?.cancel(notificationId) .then((value) { print('xxx'); Navigator.pop(context); }) .catchError((error) { print('Error cancelling notification: $error'); });

Chat GPT: 另外,你也可以把then()回調從cancelNotification()移除,然後使用await的方式等待在打印“ddd”之前的取消操作完成,然後調用printNotification函數。通過這種方式,你可以確定取消操作在打印“ddd”和調用printNotification函數之前就已經完成,代碼如下:

dart GestureDetector( onTap: () async { await myLocalNotifications.cancelNotification(context, reminder.id); print('ddd'); printNotification(); }, ),

Flutter 開發者: 我移除了then回調,並且使用了await的方式等待取消操作完成。結果是先打印了“ddd”,然後才打印“xxx”。 Chat GPT: 如果在“xxx”之前先打印了“ddd”,意味着在cancelNotification函數中的取消操作耗時比在函數外的print語句要長。這可能是showDialog或其他比較複雜的操作導致UI線程出現了延遲。解決的辦法是,你可以將print('ddd')printNotification()移到CustomAlertYesOrNo的回調方法onConfirmed內。這樣的話,他們只能在用户確認取消操作完成後才執行。例如:

dart Future<void> cancelNotification(context, int notificationId) async { showDialog( context: context, builder: (BuildContext context) { return CustomAlertYesOrNo( alertTitle: 'Confirmation', alertText: 'Do you want to delete this reminder?', onConfirmed: () async { await flutterLocalNotificationsPlugin?.cancel(notificationId); print('xxx'); Navigator.pop(context); print('ddd'); printNotification(); } ); }, ); }

Chat GPT: 這樣的話,print('ddd')printNotification() 語句只會在用户確認取消操作完成後才會執行。 Flutter 開發者:我不能在onConfirmed裏調用printNotification()。有其他解決方法嗎? Chat GPT:如果你不能在onConfirmed裏調用printNotification(),你可以通過一個回調方法通知父組件取消操作已經完成了,然後將notificationId作為一個參數傳遞過去。 例如,你可以修改cancelNotification()函數,接收一個Function(int)參數。這個函數會在取消操作完成後調用,從而觸發printNotification()函數或在取消操作完成後的需要執行的其他代碼。

dart Future<void> cancelNotification(context, int notificationId, Function(int) onCancelCompleted) async { showDialog( context: context, builder: (BuildContext context) { return CustomAlertYesOrNo( alertTitle: 'Confirmation', alertText: 'Do you want to delete this reminder?', onConfirmed: () async { await flutterLocalNotificationsPlugin?.cancel(notificationId); print('xxx'); Navigator.pop(context); onCancelCompleted(notificationId); } ); }, ); }

Chat GPT:之後,你可以修改GestureDetectoronTap 回調方法,將需要執行的回調函數傳遞給cancelNotification函數:

dart GestureDetector( onTap: () async { await myLocalNotifications.cancelNotification(context, reminder.id, (notificationId) { print('ddd'); printNotification(); }); }, ),

Chat GPT: 這樣的話,就能夠保證print('ddd')printNotification() 只會在onCancelCompleted回調被調用,也就是取消操作確認完成後才執行。

  1. 編寫文檔

這裏,使用了一個從GitHub隨便找到一個Flutter App項目,然後要求Chat GPT來寫一些文檔。

Flutter 開發者: 你能給這個App寫一份用户文檔告訴用户怎麼使用這個App嗎?App鏈接: https://github.com/sarvesh4396/notepad Chat GPT: 好的,很高興能為你編寫 Notepad Flutter App的用户文檔。下面是使用這個App的分佈指導:

如何使用Notepad App Notepad App是一個幫助你創建、編輯和刪除筆記的非常簡潔的App,下面是使用指南:

在你的手機上打開App 在主界面上,你會看到你的所有筆記的列表(如果你有創建過的話)。要添加一個新的筆記,點擊屏幕右下角的綠色的加號按鈕,然後你就可以進入到添加筆記的界面。你可以輸入筆記的標題和內容,完成之後,點擊“保存”按鈕保存筆記。 要編輯已有的筆記,在主界面上點擊這條編輯,然後就可以進入到編輯界面,你可以在編輯界面修改筆記的標題和內容。完成後點擊“編輯”按鈕可以保持編輯後的內容。 要刪除筆記,在主界面上的一條筆記上向左滑動,這時候會出現一個“刪除”按鈕,點擊這個按鈕即可刪除這條筆記。 就這樣!Notepad App通過簡單、直接的方式管理你的筆記。無論你是用於記錄工作、學習還是個人其他用途,都可以讓你一站式管理你的筆記。

  1. 給Dart文件添加註釋

這個案例看看ChatGPT能不能幫助我們編寫更易讀的代碼。我從GitHub上隨便下載了一個Dart文件,然後讓Chat GPT添加註釋來重寫代碼。下面是原文件: ```dart import 'dart:convert'; import 'package:chat_gpt_clone/models/api_model.dart'; import 'package:http/http.dart' as http;

class ApiService { Future> getDataFromOpenAI(String query) async { final response = await http.post( Uri.parse( 'https://api.openai.com/v1/engines/text-davinci-003/completions'), headers: { 'Content-Type': contentType, 'Authorization': 'Bearer $apiKey', }, body: jsonEncode({ 'prompt': query, 'max_tokens': 300, 'temperature': 0, }), );

if (response.statusCode == 200) {
  return jsonDecode(response.body);
} else {
  throw Exception('Failed to get data from OpenAI API');
}

} } ```

Flutter 開發者: 你能給下面的代碼添加註釋嗎: https://github.com/Siddharth-cmd/chat-gpt-clone/blob/main/lib/services/api_service.dart 。此外,我希望代碼能夠更加易讀易懂。 Chat GPT: 沒問題, 下面是添加註釋後的更易讀易懂的代碼:

```dart import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:chat_gpt_clone/models/message.dart';

class ApiService { // Base URL for the API final String baseUrl = "https://api.openai.com/v1/";

// API endpoint for generating a message final String endpoint = "engines/davinci-codex/completions";

// API key for accessing the OpenAI API final String apiKey;

ApiService({required this.apiKey});

Future generateMessage({required String prompt}) async { // Define the headers for the API request final headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer $apiKey', };

// Define the request body for the API request
final body = {
  'prompt': prompt,
  'max_tokens': 60,
  'temperature': 0.9,
};

// Make the API request and handle the response
final response = await http.post(Uri.parse(baseUrl + endpoint),
                                 headers: headers, body: json.encode(body));
if (response.statusCode == 200) {
  // If the response is successful, parse the JSON data and return a Message object
  final jsonBody = json.decode(response.body);
  return Message.fromJson(jsonBody['choices'][0]['text']);
} else {
  // If the response is not successful, throw an error with the status code and message
  throw Exception(
    'Failed to generate message. Status code: ${response.statusCode}. Error message: ${response.body}');
}

} } ```

  1. 編寫一個簡易的ToDo App

這是終極測試 —— 完成一個完整的Flutter ToDo App,下面是與Chat GPT的對話過程。

Flutter 開發者: 你好,能否幫我寫一個基於Flutter的簡單的待辦事項提醒App。這個App需要列出所有的待辦事項,然後有一個懸浮的按鈕來添加新的待辦事項。每個待辦事項有一個標題、描述和到期日期。

Chat GPT: 沒問題, 這是一個基礎的待辦事項提醒App,它列出了所有的待辦事項,允許你通過一個懸浮按鈕添加新的待辦事項。待辦事項的字段包括了標題、描述和到期時間。

首先,創建一個新的Flutter工程,然後打開main.dart,替換為下面的代碼:

```dart import 'package:flutter/material.dart';

void main() => runApp(ReminderApp());

class ReminderApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Reminder App', theme: ThemeData( primarySwatch: Colors.blue, ), home: ReminderList(), ); } }

class ReminderList extends StatefulWidget { @override _ReminderListState createState() => _ReminderListState(); }

class _ReminderListState extends State { List reminders = [];

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Reminders'), ), body: ListView.builder( itemCount: reminders.length, itemBuilder: (BuildContext context, int index) { return ListTile( title: Text(reminders[index].title), subtitle: Text(reminders[index].description), trailing: Text(reminders[index].dueDate.toString()), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () => _addReminder(context), tooltip: 'Add Reminder', child: Icon(Icons.add), ), ); }

void _addReminder(BuildContext context) { TextEditingController titleController = TextEditingController(); TextEditingController descriptionController = TextEditingController(); DateTime dueDate;

showDialog(
  context: context,
  builder: (BuildContext context) {
    return AlertDialog(
      title: Text('Add Reminder'),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextField(
            controller: titleController,
            decoration: InputDecoration(
              labelText: 'Title',
            ),
          ),
          TextField(
            controller: descriptionController,
            decoration: InputDecoration(
              labelText: 'Description',
            ),
          ),
          ListTile(
            title: Text('Due Date'),
            subtitle: dueDate == null
            ? null
            : Text(dueDate.toString()),
            trailing: Icon(Icons.keyboard_arrow_down),
            onTap: () async {
              DateTime picked = await showDatePicker(
                context: context,
                initialDate: DateTime.now(),
                firstDate: DateTime.now(),
                lastDate: DateTime(2100),
              );
              if (picked != null) {
                setState(() {
                  dueDate = picked;
                });
              }
            },
          ),
        ],
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: () {
            Reminder reminder = Reminder(
              title: titleController.text,
              description: descriptionController.text,
              dueDate: dueDate,
            );
            setState(() {
              reminders.add(reminder);
            });
            Navigator.pop(context);
          },
          child: Text('Save'),
        ),
      ],
    );
  },
);

} }

class Reminder { String title; String description; DateTime dueDate;

Reminder({ required this.title, required this.description, required this.dueDate, }); } ```

這個代碼定義了一個新的ReminderApp組件來設置App的標題和主題,然後將主頁設置為了ReminderList組件。

ReminderList組件是一個有狀態組件,維護了待辦事項列表。列表通過 ListView.builder顯示。 每條待辦事項使用了 ListTile 來顯示標題、描述和到期日期。 ReminderList還包括了一個懸浮按鈕,點擊這個按鈕會調研_addReminder 方法。點擊按鈕會顯示了一個對話框,允許用户輸入新的待辦事項的標題、描述和到期日期。 當用户保存新的待辦事項時,這條待辦事項會添加到待辦事項列表,然後組件會重建來更新待辦事項列表。 最後,通過一個Reminder類來定義待辦事項的屬性,包括標題、描述和到期日期。 就這些了。通過這個基礎的待辦事項提醒App可以讓你有個好的開始,並且可以擴展更多的特性。

看起來不錯,但是運行後卻報錯了,於是我把錯誤複製給了Chat GPT。

Flutter 開發者: 謝謝,但是我得到了一個錯誤: Non-nullable variable ‘dueDate’ must be assigned before it can be used.

Chat CPT:很抱歉發生了這個錯誤!這是因為 dueDate 聲明為一個非空的變量,但是沒有給初始化的值。.下面是更新後的_addReminder方法,這裏把 dueDate 初始化為 DateTime.now():

```dart void _addReminder(BuildContext context) { TextEditingController titleController = TextEditingController(); TextEditingController descriptionController = TextEditingController(); DateTime dueDate = DateTime.now();

showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('Add Reminder'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: titleController, decoration: InputDecoration( labelText: 'Title', ), ), TextField( controller: descriptionController, decoration: InputDecoration( labelText: 'Description', ), ), ListTile( title: Text('Due Date'), subtitle: dueDate == null ? null : Text(dueDate.toString()), trailing: Icon(Icons.keyboard_arrow_down), onTap: () async { DateTime picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime(2100), ); if (picked != null) { setState(() { dueDate = picked; }); } }, ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Cancel'), ), ElevatedButton( onPressed: () { Reminder reminder = Reminder( title: titleController.text, description: descriptionController.text, dueDate: dueDate, ); setState(() { reminders.add(reminder); }); Navigator.pop(context); }, child: Text('Save'), ), ], ); }, ); } ```

有趣!Chat GPT懂得分析錯誤,並且解釋了原因和修正了代碼錯誤。再次運行代碼,卻報了其他的錯誤,於是繼續問 Chat GPT.

Flutter 開發者: 錯誤: A value of type ‘DateTime?’ can’t be assigned to a variable of type ‘DateTime’ because ‘DateTime?’ is nullable and ‘DateTime’ isn’t.

Chat GPT: 抱歉發生了錯誤。以為 dueDate聲明為一個非空對象, 它不能賦予空值。然而,如果用户不選擇日期,那從showDatePicker 會返回空值。要修復這個問題,需要給dueDate一個默認值() (如 DateTime.now()), 然後再重新賦值的時候檢查是否為空,下面是更新後的代碼。

```dart void _addReminder(BuildContext context) { TextEditingController titleController = TextEditingController(); TextEditingController descriptionController = TextEditingController(); DateTime dueDate = DateTime.now();

showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('Add Reminder'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: titleController, decoration: InputDecoration( labelText: 'Title', ), ), TextField( controller: descriptionController, decoration: InputDecoration( labelText: 'Description', ), ), ListTile( title: Text('Due Date'), subtitle: dueDate == null ? null : Text(dueDate.toString()), trailing: Icon(Icons.keyboard_arrow_down), onTap: () async { DateTime? picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime(2100), ); if (picked != null) { setState(() { dueDate = picked; }); } }, ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Cancel'), ), ElevatedButton( onPressed: () { Reminder reminder = Reminder( title: titleController.text, description: descriptionController.text, dueDate: dueDate, ); setState(() { reminders.add(reminder); }); Navigator.pop(context); }, child: Text('Save'), ), ], ); }, ); } ```

Flutter developer: 很棒,謝謝!你能在主頁按卡片的形式顯示待辦事項嗎,並且基於是否過期為每個待辦事項添加一個不同的圖標。同時,請格式化數據以只顯示日期而不顯示具體的時間。

Chat GPT: 好的, 這是更新後按卡片顯示待辦事項的代碼,過去和未來到期的待辦事項會有不同的圖標,並且到期日期也格式化為只保留了日期部分:

dart @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Reminders'), ), body: ListView.builder( itemCount: reminders.length, itemBuilder: (BuildContext context, int index) { Reminder reminder = reminders[index]; IconData iconData = reminder.dueDate.isAfter(DateTime.now()) ? Icons.access_time : Icons.watch_later; return Card( child: ListTile( leading: Icon(iconData), title: Text(reminder.title), subtitle: Text( DateFormat('yyyy-MM-dd').format(reminder.dueDate), ), trailing: IconButton( icon: Icon(Icons.delete), onPressed: () { setState(() { reminders.removeAt(index); }); }, ), ), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () => _addReminder(context), tooltip: 'Add Reminder', child: Icon(Icons.add), ), ); }

Chat GPT: 在這個版本中,ListView.builder 組件用來顯示待辦事項,對於每一個待辦事項都使用Card組件來顯示他們的標題、描述和到期日期。使用了一個 icon 來指示這個待辦事項是否是過去的還是未來的。使用了 DateFormat 類將到期日期格式化為 yyyy-MM-dd, 這樣只會顯示日期,而不會顯示具體的時間。

Chat GPT: 記住 DateFormat 類是 intl package中的,因此在使用之前需要引入這個package ,因此需要在你的Dart文件頂部添加下面導入的代碼:

dart import 'package:intl/intl.dart'; 結果是我在幾分鐘內寫了一個完整功能的ToDo清單App,雖然是個非常基礎的App,但是運行正常,下面是App的界面截圖,看起來還是相當不錯的。 image.png

總結

可以看到,Chat GPT是一個可以大幅提升Flutter 開發者生產力的偉大工具。在本文的案例中,Chat CPT成功搞定了我們的需求。

在某些案例下,我們需要使用2到3個問題才能得到需要的答案,也就是我們需要花點時間思考如何向Chat GPT提問,即便一開始你的問題不那麼清晰,但是可以在後面追加問題來得的準確的答案。

我是島上碼農,微信公眾號同名。如有問題可以加本人微信交流,微信號:island-coder

👍🏻:覺得有收穫請點個贊鼓勵一下!

🌟:收藏文章,方便回看哦!

💬:評論交流,互相進步!

本文正在參加「金石計劃」