Skip to content

OriXEnos/TaskFlow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TaskFlow (Todo-List)

TaskFlow คือ App (To-do-List) บริหารจัดการงาน (Task Management App) ที่ออกแบบมาเพื่อช่วยให้ผู้ใช้สามารถ จัดลำดับความสำคัญ วางแผน และ ติดตามงานได้อย่างเป็นระบบ โดยเน้น UI ที่เรียบง่าย ใช้งานง่าย และพัฒนาด้วย Flutter

Table of Content

Features

  • 📝 สร้าง / แก้ไข / ลบ Task ได้อย่างสะดวก
  • 🎯 กำหนดระดับความสำคัญของงาน (High / Medium / Low)
  • 🗓️ กำหนดตั้งเวลาของตารางงาน
  • 📊 แสดงสถานะความคืบหน้าของงาน
  • 🎨 ยิง API เพื่อดึงรูปภาพแมวมาใช้เป็นฉากพื้นหลัง
  • 🔐 ระบบ Login / Logout
  • 👤 ระบบสมัครสมาชิก (Sign Up)
  • 🔍 ระบบค้นหางาน (Search)
  • 🔑 ระบบ Reset Password
  • 📱 รองรับ Mobile

Packages

  • Packages/Library ที่ใช้ทำงาน ร่วมกับ Flutter
  • Download ได้จาก Link นี้ : The official repository for Dart and Flutter packages.
    • cupertino_icons:

      • #ดึง icon Style แบบ iOS มาใช้งาน
    • intl:

      • #ใช้สำหรับ รองรับหลายภาษา , เพื่อ Format(แปลง) ข้อมูล เช่น วันที่ เวลา ตัวเลข เงิน ให้ตรงกับประเทศ/ภาษา ตามภูมิภาคนั้น
    • dio:

      • #HTTP client สำหรับเรียก REST API
    • bloc:

      • #ใช้จัดการ business logic และ state
    • shared_preferences:

      • #ใช้สำหรับ เก็บข้อมูล ที่มีการเปลี่ยนแปลงในหน้า UI ลงไปในเครื่อง , กรณีที่ต้องการ เรียกข้อมูลนำมาใช้งานอีกครั้ง เช่น คำนวณ หรือ เปลี่ยนแปลงค่าใหม่
    • equatable:

      • #ใช้เพื่อเปรียบเทียบ object , ถ้าค่า object เหมือนกัน จะได้ไม่ต้อง rebuild UI ใหม่ทั้งหน้า
    • bloc_test:

      • #ใช้เขียน unit test สำหรับทดสอบ BLoC , ว่าการทำงานถูกต้องไหม , มี Bug หรือเปล่า
    • mocktail:

      • #ใช้ mock object(สร้างข้อมูลปลอม) ตอน test , โดยไม่ต้องไปแตะของจริง , ใช้ร่วมกับ Unit Testing
    • form_field_validator:

      • #ใช้สำหรับ ตรวจสอบข้อมูลที่ถูกป้อนเข้ามาในช่อง TextFormField , ว่าข้อมูลพิมพ์มาในช่องกรอกนั้น ถูกต้องตามเงื่อนไขไหม
    • firebase_core:

      • #เชื่อมต่อ Firbase กับ Flutter , เพื่อเรียกใช้เครื่องมือจาก Firebase
    • firebase_auth:

      • #เรียกใช้เครื่องมือ ระบบ Login / Register ใน Firebase
    • cloud_firestore:

      • #เรียกใช้เครื่องมือ ฐานข้อมูล NoSQL ของ Firebase , ใช้เก็บข้อมูลแบบ real-time
    • flutter_bloc:

      • #ใช้เชื่อมต่อ bloc เข้ากับ Flutter ในหน้า UI
    • google_fonts:

      • #เรียกใช้งาน Font ของ Google มาใช้งานใน Flutter
    • transparent_image:

      • #เรียกใช้ เครื่องมือ ทำให้รูปภาพมีความโปร่งใสมากขึ้น
    • flutter_launcher_icons:

      • #ใช้สร้าง App Icon อัตโนมัติ

Tech Stack

  • Framework: Flutter
  • Language: Dart
  • Database: Firebase
  • State Management: Bloc
  • Design: Figma
  • Version Control: Git & GitHub

UI UX Design Figma

Project TaskFlow ได้มีการออกแบบหน้า UI ล่วงหน้าด้วย Figma เพื่อกำหนดโครงสร้างหน้าจอ (Layout), Component และ User Flow ก่อนนำไปพัฒนาเป็นแอปด้วย Flutter

ตัวอย่างหน้าตา UI

image alt image alt

ตัวอย่างการใช้ Grid System ใน Project

image alt

  • 4-Column Grid For Mobile
  • 8-Column Grid For Tablet
  • 12-Column Grid For Website

📐 4-Column Grid Layout

Project TaskFlow ออกแบบ UI โดยใช้ 4-Column Grid System เพื่อให้เลย์เอาต์มีความเป็นระเบียบ รองรับการพัฒนาเป็น Mobile Application ได้ง่าย และสอดคล้องกับหลัก Responsive Design

🟥 Columns (Red area):

  • คือพื้นที่ “คอลัมน์จริง” ที่ใช้วางเนื้อหา , เช่น Card, Text, Button, List, Image

🟩 Gutters (Light green area):

  • เป็นช่องเว้นระยะห่างระหว่างคอลัมน์ , ช่วยให้ เนื้อหาไม่ติดและชิดกันมาก และ ทำให้อ่านง่าย ,

🟪 Margins (Light purple area):

  • ขอบซ้าย–ขวาของหน้าจอ , คือ ระยะห่างของขอบ ระหว่างหน้าจอกับ Column แรก/สุดท้าย , ป้องกันไม่ให้เนื้อหาชิดขอบจอเกินไป

เหตุผลที่เลือกใช้ 4 Columns

  • ช่วยให้การจัดวางองค์ประกอบมีความสมดุล , เป็นระเบียบเรียบร้อย
  • รองรับการขยาย Layout ในอนาคต

UI/Pages

  • Splash Screen
  • SignIn Screen
  • SignUp Screen
  • Forget Password Screen
  • Welcome Screen
  • Create Task Screen
  • EditTask Screen
  • Search Screen
  • Setting Profile Screen
  • See All Tasks Screen

Design Systems

  • ใช้ Component Library (UI Kit) เพื่อลดความซ้ำซ้อน

  • กำหนดสี, Typography และ Spacing ให้สม่ำเสมอทั้งแอป

  • ออกแบบให้รองรับ Mobile เป็นหลัก (Mobile-first)

  • Note : กระบวนการทำงาน UI / Design System / Frontend (เชิงระบบ)

    • ⭐ AUDIT (ตรวจสอบ)

      • ตรวจสอบ งาน design จาก designers , ก่อนจะนำไปเขียน Code จริง
    • ⭐ DESIGN & DOCUMENTATION

      • ออกแบบ + ทำเอกสาร
      • สร้าง “ระบบ” ให้คนอื่นนำไปใช้ต่อได้ ไม่ใช่แค่ ออกแบบสวยอย่างเดียว
    • ⭐ QA (Quality Assurance)

      • ตรวจสอบคุณภาพของงาน ตั้งแต่ ออกแบบ → เขียน Code → ก่อนปล่อยใช้งานจริง
      • 📌 เพื่อให้มั่นใจว่า “ของที่ปล่อยไป ไม่พัง ไม่มั่ว ไม่หลุดตามมาตรฐาน”
    • ⭐ MAINTAIN (ดูแลระยะยาว)

      • ค่อยติดตาม ดูแล-แก้ไข-ปรับปรุง ของงาน, หลังจากที่ ปล่อย App ไปบน PlayStore แล้ว
      • ดูแล และ ติดตามผล ในระยะยาว หลังปล่อยใช้งานเรียบร้อย
  • Note : หัวใจสำคัญของการใช้งาน Figma

    • Auto Layout

      • ทำให้ UI ขยาย / หด ได้อัตโนมัติ , โดยไม่ต้องไปปรับเองทุกจุด
    • Components

      • ใช้สร้าง ของที่นำกลับมาใช้ซ้ำได้ (reuse)
    • Variables

      • ค่ากลาง (Reusable values) ที่เรากำหนดไว้ครั้งเดียว แล้วหยิบค่ากลาง นำไปใช้ซ้ำกับหลายๆที่ , หลาย ๆ ส่วนของ Design
    • Variants

      • Component เดียว , แต่แสดงหน้าตา UI หลาย “สถานะ” , "หลาย Style" ,"หลายแบบ" (state / version)
      • ตัวอย่าง

        • 🔘 Button

          • default
          • hover
          • pressed
          • disabled
        • 🔘 default

          • สภาพ ปกติของปุ่ม , โดยยังไม่มีการ แตะ , กด หรือะไร
        • 🖱️ hover

          • เลื่อนเมาส์ มาวางเหนือปุ่ม (ยังไม่กด)
          • ตัวอย่าง:
            • สีปุ่ม จะดูเข้มขึ้นทันที
            • 👉 บอกผู้ใช้ว่า “ปุ่มนี้กดได้นะ”
        • 👆 pressed (หรือ active)

          • ขณะกำลังกดปุ่มอยู่ (คลิกค้าง / แตะ)
        • 🚫 disabled

          • ปุ่มถูกปิดใช้งาน
          • กดไม่ได้
          • ตัวอย่าง:
            • สีเทา
            • ตัวอักษรจาง
  • 🔗 Figma Design – My Project

  • ศึกษาเพิ่มเติมได้ที่ :

Project Structure

โครงสร้าง Project TaskFlow ถูกออกแบบตามแนวคิด Clean Architecture + BLoC Pattern เพื่อให้ Code แยกหน้าที่ชัดเจนดูแลรักษาและทดสอบได้ง่าย

lib/
│
├─ main.dart               
├─ app_route.dart          
│
└─ src/
  ├─ bloc/               
  │  ├─ sign_in/
  │  ├─ sign_up/
  │  ├─ sign_out/
  │  ├─ forget_pass/
  │  ├─ search/
  │  ├─ week_calendar/
  │  ├─ cat_api_image/
  │  └─ app_bloc_observer.dart
  │
  ├─ data/                
  │  ├─ models/          
  │  ├─ api_repository.dart
  │  ├─ auth_repository.dart
  │  └─ task_repository.dart
  │
  └─ pages/                
     ├─ splash_page.dart
     ├─ sign_in_page.dart
     ├─ sign_up_page.dart
     ├─ forget_password_page.dart
     ├─ welcome_page.dart
     ├─ create_task_page.dart
	 ├─	edit_task_page.dart
     ├─ search_page.dart
     ├─ see_all_list.dart
     └─ setting_profile_page.dart
	   
test/
│
├─ forget_pass_bloc_test.dart                        
├─ search_bloc_test.dart                    
└─ widget_test.dart                          

อธิบาย Project Structure

  • main.dart

    • เป็นจุดเริ่มต้นเรียกใช้ Function การทำงาน ของ App Flutter
    • ใช้ตั้งค่าเริ่มต้นต่าง ๆ ของ App , เช่น ไม่ว่าจะเป็นการกำหนด Routing ในการเปลี่ยนสลับไปยังหน้าเมนูอื่นๆ
  • app_route.dart

    • ใช้สำหรับ จัดการเส้นทางการนำทาง (Navigation / Routes) ของ App
    • รวม ชื่อ route ทั้งหมดไว้ที่เดียว
    • จัดการการเปลี่ยนหน้า (Page Navigation)
    • ลดการเขียน Navigator.push() ซ้ำ ๆ ทีละหน้าแทน
    • ทำให้ Code เป็นระเบียบและแก้ง่าย
  • bloc/

    • คือ Folder ที่เก็บ Business Logic ของ App ตามสถาปัตยกรรม BLoC (Business Logic Component) ทำหน้าที่แยก “ตรรกะการทำงาน” ออกจาก “หน้าจอ UI” ให้ Code เป็นระเบียบ ทดสอบง่าย และดูแลง่าย

    • จะประกอบไปด้วย Files ต่างๆที่ทำงานเชื่อมต่อกับ Bloc เช่น , ระบบ Login , ระบบ Register , ระบบการจัดการปฎิทิน วัน/เดือน/ปี

    • Bloc

      • ควบคุมการทำงานหลัก รับ event → ประมวลผล → ส่ง state ไปแสดงผลหน้าจอ UI
    • Event

      • เหตุการณ์ที่เกิดจากผู้ใช้หรือระบบ (เช่น กดปุ่ม, โหลดข้อมูล)
    • State

      • สถานะของหน้าจอ (เช่น กำลังโหลด, โหลดสำเร็จ, error)
    • 🏗️ Bloc Architecture Overview

			graph TD
			User[User] --> UI[UI Widgets]
			subgraph BLoC_Layer [BLoC Layer]
			Event[Event]
			Bloc[BLoC]
			State[State]
			end
			subgraph Data_Layer [Data Layer]
			Repository[Repository]
			DataSource[API / Firebase / Server]
			end
			UI -->|dispatch| Event
			Event --> Bloc
			Bloc -->|emit| State
			State --> UI
			Bloc -->|request data| Repository
			Repository --> DataSource
			DataSource --> Repository
			Repository --> Bloc
Loading
  • สรุป :

    เหตุผลที่นำ Bloc มาใช้ใน Project , เพื่อแยกการทำงานหน้าที่ให้มันชัดเจน

    • UI (pages/widgets) → แสดงผลอย่างเดียว
    • BLoC → เอาไว้จัดการ Logic / State
    • Repository (data) → เอาไว้จัดการข้อมูล (API, Firebase, DB)
    • BLoC ช่วยให้ rebuild UI เท่าที่จำเป็น , ไม่ทำให้ UI rebuild ทั้งหน้าโดยไม่จำเป็น โดย ทำให้ App มีการทำงาน Performance ที่เสถียรดีขึ้น
  • app_bloc_observer.dart

    • ใช้ debug / log การทำงานของ Bloc ทั้งแอป
    • ดูว่า event ไหนถูกเรียก และ state เปลี่ยนเป็นอะไร
  • data/

    • เป็น Folder ที่รับผิดชอบเรื่อง , การดึงข้อมูล , การบันทึกข้อมูล
    • การแปลงข้อมูลให้อยู่ในรูปแบบที่ App ใช้งานได้ โดย , ไม่เกี่ยวกับ UI โดยตรง
  • models/

    • คือ Folder ที่ใช้เก็บ โครงสร้างข้อมูล (Data Model / Entity) ของ App พูดง่าย ๆ คือเป็น พิมพ์เขียวของข้อมูล ที่ App ใช้งาน
    • กำหนดรูปแบบข้อมูล
    • แปลงข้อมูลระหว่าง , JSON ↔ Object (จาก API / Firebase) , - เป็นชนิดข้อมูลที่ BLoC สามารถเรียกใช้งาน
  • api_repository.dart

    • เป็น File ที่รวม Function การทำงาน ไว้ใช้ การเรียก API
    • ทำหน้าที่ แปลง JSON → Model , เพื่อให้ Bloc สามารถนำข้อมูลไปใช้งานได้ง่าย
    • หาก API มีการเปลี่ยนแปลง หรือแก้ไข ก็จะไม่กระทบ BLoC / UI โดยตรง ,
  • auth_repository.dart

    • รวม Function ที่ใช้จัดการ ระบบ Login / สมัครสมาชิก / ออกจากระบบ / Reset รหัสผ่าน โดยใช้ Firebase Authentication และ เรียกใ้ช Firestore เข้ามาทำงาน
    • จะไม่เรียกใช้ Function ผ่านการทำงาน Bloc / UI โดยตรง , แต่ให้ไปเรียก Repository ที่ทำหน้าที่เป็นตัวกลางแทน
  • task_repository.dart

    • รวมฟังก์ชันที่ใช้จัดการข้อมูล Task ใน Firestore , เช่น เพิ่ม, ดึง, แก้ไข, ลบ
  • pages/

    • Folder ที่เก็บหน้าจอ (Screens / Pages) ของ App
    • ไม่ควรมี Function logic หนัก ๆ หรือเรียก API โดยตรง ในหน้า UI
    • สามารถใข้เชื่อมต่อกับ BLoC ได้
    • ประกอบไปด้วย Files :

      • 🚀 splash_page.dart - หน้าแรกสุดของ App - แสดง Logo / Loading

      • 🔐 sign_in_page.dart - หน้าเข้าสู่ระบบ

      • 📝 sign_up_page.dart - หน้าสมัครสมาชิก

      • 🔁 forget_password_page.dart - หน้าขอ Reset รหัสผ่าน

      • 👋 welcome_page.dart - หน้า แสดงภาพรวมของ Task ทั้งหมด

      • create_task_page.dart - หน้าสร้าง Task ใหม่

      • 🛠️ edit_task_page.dart - หน้าแก้ไข ข้อมูล Task

      • 🔍 search_page.dart - หน้าค้นหา Task

      • 📋 see_all_list.dart - หน้าแสดงรายการ Task ทั้งหมด

      • ⚙️ setting_profile_page.dart - หน้าตั้งค่า Profile - หน้าสำหรับ Logout

  • test/

    • เป็น Folder ที่รวมการทำงานในส่วนของ Unit Testing ใช้สำหรับทดสอบ Code , ตรวจสอบหา Bug , ข้อผิดพลาดของการทำงานในระบบ

    • ตรวจสอบว่า function ทำงานถูกต้องไหม

    • ใช้ตรวจสอบว่าเมื่อ

      • ส่ง Event เข้าไป , ให้ Bloc ประมวลผล , แล้ว State ที่ได้ออกมาถูกต้องหรือไม่
    • forget_pass_bloc_test.dart

      • ใช้สำหรับ ทดสอบ กรณีที่ ระบบ ได้ทำการ Reset Password ไปยัง Email สำเร็จ หรือไม่ หากส่งสำเร็จ จะให้แสดงผลลัพธ์อะไรกลับออกมา
      • ใช้สำหรับ ทดสอบ กรณีที่ Internet ล่ม , server error แล้วระบบ ได้ทำการ Reset Password ไปยัง Email ไม่สำเร็จ หากส่งไม่สำเร็จ จะให้แสดงผลลัพธ์อะไรกลับออกมา
    • search_bloc_test.dart

      • ใช้สำหรับ ทดสอบ กรณีที่ หากเป็นสถานะตอนเริ่มต้น , ข้อความในช่อง ค้นหา ต้องว่าง , ต้องไม่มีการแสดงผลลัพธ์ในการค้นหา
      • ใช้สำหรับ ทดสอบ กรณีที่ เราใส่ชื่อ Task ในช่องค้นหา , แล้วชื่อ Task มันมีอยู่ในระบบไหม , แล้ว แสดงผลลัพธ์ในช่องค้นหาไหม ,
      • ใช้สำหรับ ทดสอบ ลองส่ง Event ชื่อ ClearSearch() เข้าไปใน Bloc , ข้อความในช่องค้นหาชื่อ Task , จะถูกล้างเป็น ค่าว่างใน ช่องค้นหาไหม
    • widget_test.dart

      • ใช้สำหรับ ทดสอบ หน้าจอและ widget ของแอป เพื่อให้มั่นใจว่า UI แสดงผลและทำงานถูกต้อง
      • มีการ เพิ่ม Repository ใน widget_test.dart เพราะ MyApp ถูกออกแบบให้ต้องรับ dependency(ทำงานแบบพึ่งพาอาศัยกัน) ให้ทำงานใน App ได้ , ไม่งั้นจะ Error

⭐ Widget Lifecycle

  • วงจรชีวิตของ widget ตั้งแต่ :

    • สร้าง → แสดงผล → อัปเดต → ถูกทำลาย
  • ประโยชน์

    • ช่วย ป้องกัน bug และ memory leak
    • ช่วย ปรับปรุง performance (ไม่ rebuild เกินจำเป็น)
  • 📌 ประเภทของ Widget ตาม Lifecycle

    • StatelessWidget

      • ใช้แสดงผลอย่างเดียว ไม่มีการเปลี่ยนแปลงค่า State
      • Build แค่ครั้งเดียว
    • StatefulWidget

      • มี Lifecycle , มีการเปลี่ยนแปลงข้อมูล หรือ ค่า state ในหน้า UI บ่อยๆ
  • 🔄 Flow ของ StatefulWidget (Lifecycle)

     	createState()    
     	   ↓
     	initState()
     	   ↓
     	build()					
     	   ↓
     	setState() → build() (วนซ้ำ)
     	   ↓
     	dispose()
    
    • 🔹 createState()

      • สร้าง State object , ถูกเรียก ครั้งเดียว , ใช้ State นี้เก็บข้อมูลค่าที่มีการเปลี่ยนแปลง
    • 🔹 initState()

      • ถูกเรียก ครั้งเดียว
      • ใช้สำหรับเตรียมค่าเริ่มต้น เช่น :
        • เรียก API ครั้งแรก
        • กำหนดค่า controller
    • 🔹 build()

      • สร้าง / อัปเดต การเปลี่ยนแปลงหน้า UI , จากค่า state ปัจจุบัน
      • 📌 สำคัญมาก:

        build ต้อง ทำงานเร็ว และ ไม่มี logic หนัก

    • 🔹 setState()

      • แจ้ง Flutter ว่า หน้า UI จะมีการ Update ข้อมูลใหม่น่ะ
      • Flutter จะเก็บค่า state ที่มีการเปลี่ยนแปลง
      • แล้วไปเรียก build() ใหม่
    • 🔹 dispose()

      • เป็นขั้นตอนสุดท้าย ใช้ ปิด / ล้างค่า / ยกเลิกการทำงานของ resource ต่าง ๆ

      • ใช้เมื่อ มีการเปลี่ยนหน้า , หรือปิดการใช้งาน App

      • ตัวอย่าง Code

       	import 'package:flutter/material.dart';
      
       	void main() {
       	  runApp(const MyApp());
       	}
      
       	/// Widget หลักของแอป
       	class MyApp extends StatelessWidget {
       	  const MyApp({super.key});
      
       	  @override
       	  Widget build(BuildContext context) {
       	    return const MaterialApp(
       	      home: CounterPage(),
       	    );
       	  }
       	}
      
       	/// StatefulWidget
       	/// - ใช้เมื่อมี state ที่เปลี่ยนแปลงได้
       	class CounterPage extends StatefulWidget {
       	  const CounterPage({super.key});
      
       	  /// 1️⃣ createState()
       	  @override
       	  State<CounterPage> createState() {
       	    print('createState()');
       	    return _CounterPageState();
       	  }
       	}
      
       	/// State class
       	class _CounterPageState extends State<CounterPage> {
       	  int counter = 0;
      
       	  /// 2️⃣ initState()
       	  @override
       	  void initState() {
       	    super.initState();
       	    print('initState()');
      
       	    counter = 0; // กำหนดค่าเริ่มต้น
       	  }
      
       	  /// 3️⃣ build()
       	  @override
       	  Widget build(BuildContext context) {
       	    print('build()');
      
       	    return Scaffold(
       	      appBar: AppBar(
       	        title: const Text('Widget Lifecycle Demo'),
       	      ),
       	      body: Center(
       	        child: Column(
       	          mainAxisAlignment: MainAxisAlignment.center,
       	          children: [
       	            const Text(
       	              'Counter value:',
       	              style: TextStyle(fontSize: 18),
       	            ),
       	            Text(
       	              '$counter',
       	              style: const TextStyle(fontSize: 32),
       	            ),
       	            const SizedBox(height: 20),
      
       	            /// ปุ่มกดเพื่อเรียก setState()
       	            ElevatedButton(
       	              onPressed: () {
       	                /// 4️⃣ setState()
       	                setState(() {
       	                  counter++;
       	                  print('setState() → counter = $counter');
       	                });
       	              },
       	              child: const Text('Increment'),
       	            ),
       	          ],
       	        ),
       	      ),
       	    );
       	  }
      
       	  /// 5️⃣ dispose()
       	  @override
       	  void dispose() {
       	    print('dispose()');
       	    super.dispose();
       	  }
       	}
       	```
      

⭐ Asynchronous

  • ไม่ต้องรอให้คำสั่งใดคำสั่งหนึ่งเสร็จก่อน ถึงจะไปทำคำสั่งถัดไปได้

  • เหมาะกับงาน

    • เรียก API
    • อ่าน File
    • เข้าถึงฐานข้อมูล
    • หน่วงเวลา (delay)
  • ประโยชน์

    • 👉 ช่วยให้ ** App ไม่ค้าง / UI ไม่หยุดทำงาน**
  • 🔹 Future

    • เดียวจะมีค่าที่จะได้มาในอนาคตน่ะ , แต่ตอนนี้ยังไม่มีค่า
  • 🔹 async

    • ใช้ประกาศว่า Function นี้ ทำงานแบบ Asynchronous น่ะ
  • 🔹 await

    • รอคำสั่งในบรรทัดนี้ ทำงานให้เสร็จ , แล้วค่อยไปทำงานคำสั่งในบรรทัดถัดไป

    • ตัวอย่าง Code

       	Future<void> loadData() async {
       	  print('Loading...');
       	  await Future.delayed(Duration(seconds: 2));
       	  print('Data loaded');
       	}

⭐ Flutter Structure Tools

  • เป็น เมนู ที่ใช้สำหรับ ดูโครงสร้าง Widget Tree ของแอป Flutter แบบเป็นลำดับชั้น ใน Android Studio Code

  • ทำงานร่วมกับ Flutter Inspector

  • ใช้ทำอะไรได้บ้าง

      MaterialApp
       └─ Scaffold
          └─ AppBar
          └─ Column
             ├─ Text
             ├─ ElevatedButton
             └─ ListView
    
    • ดู โครงสร้าง Widget ทั้งหมด
    • ตรวจว่า layout ซ้อนลึกเกินไปหรือไม่
    • หา widget ที่ทำให้ UI ช้า
  • เปิดได้ที่

    • View -> Tool Windows -> Structure
  • Conceptual example

    • ในตัวอย่างต่อไปนี้ ภาพหน้าจอแรกจะแสดงไอคอน 3 อันพร้อมป้ายกำกับ (label) และภาพหน้าจอที่สองจะแสดงโครงร่างการจัดวางของแถว (rows) และคอลัมน์ (columns)

    • Container ใช้สำหรับ :

      • เพิ่ม padding (ระยะด้านใน)
      • เพิ่ม margin (ระยะด้านนอก)
      • ใส่ border
      • ใส่ สีพื้นหลัง
      • ปรับขนาด ฯลฯ
    • Row ทั้งแถวถูกวางไว้ใน Container เพื่อเพิ่ม padding รอบ ๆ แถว

    • Column + Container ใช้เพื่อจัดระยะห่าง Layout , เนื่องจาก Column ไม่มี padding / margin , จึงต้องครอบด้วย Container

    • Text แต่ละอันถูกวางไว้ใน Container เพื่อเพิ่ม margin

  • ศึกษาเพิ่มเติมได้ที่ :

⭐ Flutter DevTools

  • เป็นเครื่องมือสำหรับ Debug วิเคราะห์ และปรับปรุงประสิทธิภาพ App Flutter

    • ช่วยตรวจสอบ Performance (ประสิทธิภาพการทำงานของ App)
    • ดูว่า function ไหน ทำให้ CPU ทำงานหนักจนเกินไป
    • ตรวจสอบ memory usage (หน่วยความจำใช้ไปเท่าไร)
    • ดู log จาก App แบบ real-time
  • How to launch DevTools

    • visual studio code

      • เปิด Visual Studio Code ขึ้นมา
      • ไปที่ เมนู Run and Debug
      • ทำการคลิก create launch.json file.

      • ให้ทำการเปิด File launch.json , แล้วแก้ไข "name": เป็น Debug , Profile , Release

        // Use IntelliSense to learn about possible attributes.
        // Hover to view descriptions of existing attributes.
        // For more information, visit: https://go.microsoft.com/fwlink/?					linkid=830387
        "version": "0.2.0",
        "configurations": [
            {
                    "name": "Debug",
                    "request": "launch",
                    "type": "dart"
                },
                {
                    "name": "Profile",
                    "request": "launch",
                    "type": "dart",
                    "flutterMode": "profile"
                },
                {
                    "name": "Release",
                    "request": "launch",
                    "type": "dart",
                    "flutterMode": "release"
                }
            ]
        }
        
        • Debug mode

          • เป็นโหมดการทำงานขณะพัฒนาที่เน้นการค้นหาและแก้ไขข้อผิดพลาด (Debug) โดยมี Feature สำคัญเช่น Hot Reload เพื่อดูผลลัพธ์ Code ที่แก้ทันที, แสดง Debugger เพื่อตรวจสอบ Code ทีละบรรทัด
          • 📌 สามารถใช้ DevTools ใช้ได้เต็มรูปแบบ
          • ข้อเสีย:
            • App จะ ช้า และ File ใหญ่ กว่าปกติมาก
          • คำเตือน: ⚠️
            • ห้ามวัดความเร็ว Performance App ในโหมดนี้เด็ดขาด เพราะมันช้าเป็นปกติครับ
            • ควรใช้ตอนไหน:
              • เขียน Code /แก้บั๊ก
        • Profile mode

          • เป็นโหมดที่ เน้นใช้ วัดประสิทธิภาพ (Performance) ใน App เป็นหลัก
          • 📌 DevTools เหมาะที่สุดในโหมดนี้
          • การทำงาน:
            • จะคอมไพล์ Code คล้ายกับ Release Mode (เพื่อให้ได้ความเร็วที่ใกล้เคียงความจริงที่สุด)
            • แต่จะ เปิดระบบ Tracing ไว้ เพื่อให้เครื่องมือ DevTools สามารถเข้าไปจับข้อมูลได้ (เช่น วัด FPS, ดูการใช้ Memory, ดู CPU)
          • ข้อจำกัด:
            • ห้าม Run บน Simulator/Emulator (ผลที่ได้จะไม่ตรงความจริง) ต้อง Run บนเครื่องจริงเท่านั้น
            • ❌ ไม่มี Hot Reload
          • ควรใช้ตอนไหน:
            • เมื่อคุณรู้สึกว่า "App กระตุก", "เลื่อนหน้าจอไม่ลื่น", หรือ "กินแบตเตอรี่" ให้ Run โหมดนี้แล้วเปิด DevTools เพื่อหาสาเหตุครับ
        • Release mode

          • โหมดนี้ มีไว้เพื่อ "ส่ง App ขึ้นไปยัง Store" (Google Play / App Store) หรือส่งให้ผู้ใช้ ได้ใช้งานจริง
          • การทำงาน:
            • เร็วที่สุด & เล็กที่สุด: Code จะถูกบีบอัด (Minified) และตัด Function Debugging/Tracing ออกทั้งหมด
          • ข้อควรระวัง:
            • Flutter DevTools จะไม่ทำงาน: คุณจะ Debug ดูตัวแปร หรือดู Log ไม่ได้แล้ว (หรือดูได้ยากมาก)
            • Error บางอย่างอาจไม่โชว์: ในโหมด Debug ถ้ามี Error จอจะแดง (Red Screen of Death) แต่ใน Release App อาจจะแค่ค้างหรือปิดไปเลย (Crash)
          • *ควรใช้ตอนไหน:
            • ขั้นตอนสุดท้ายเมื่อทดสอบเสร็จแล้ว และต้องการ Build File .apk หรือ .ipa
        • ให้ทำการโหลด Extension Flutter DevTools มาไว้ใน VS code , แล้วทำการ Run emulator เพื่อทดสอบ App

    • Android studio code

      • Run App Flutter ก่อน
      • ทำการ เลือก Emulator / มือถือจริง แล้วกด ▶️ Run
      • หรือใช้โหมดที่เหมาะกับการวัด Performance:

        flutter run --profile ⚠️ DevTools จะไม่ทำงาน ถ้า App ยังไม่ Run

      • ไปที่เมนู:
        • View → Tool Windows → Flutter DevTool
        • ✅ ถ้าเชื่อมต่อสำเร็จ จะเห็น:
          • Performance
          • CPU Profiler
          • Memory
          • Network
    • Menu UI/DevTools

      • 🔴 Performance

        • ใช้สำหรับ วิเคราะห์ประสิทธิภาพ การทำงาน ของ App
      • 🔴 CPU Profiler

        • ดูว่า Code ส่วนไหนที่ให้ CPU ทำงานหนัก / ช้า
        • เหมาะเมื่อ:
          • FPS ตก
          • Animation ไม่ลื่น
          • มี logic หนักใน build() หรือ setState()
      • 🔴 Memory

        • ดูการใช้หน่วยความจำ (RAM)
        • เหมาะเมื่อ:
          • App ใช้ RAM เพิ่มเรื่อย ๆ
          • App crash หลังใช้งานนาน
          • หรือสงสัยลืมปิด Controller / StreamBuilder
      • 🔴 Network

        • ตรวจสอบการเรียก API และความเร็วอินเทอร์เน็ต
        • เหมาะเมื่อ:
          • โหลดข้อมูลช้า
          • API ถูกเรียกหลายครั้งโดยไม่ตั้งใจ
      • 🟢 สีของแท่งกราฟ

        • 🟢 -> 🟦 UI (UI Thread) → build หนัก

          • เวลาที่ Flutter ใช้ :
          • สร้าง widget tree และ คำนวณ Layout
          • ตัดสินใจว่า “ต้องวาดหน้า UI อะไรบ้าง”
          • Run build()
          • ==📌 ถ้าสีฟ้านี้สูง → แปลว่า build หนัก / logic เยอะ / rebuild บ่อย==
        • 🟢 -> 🔵 Raster (GPU Thread) → วาดภาพหนัก

          • เวลาที่ Flutter ใช้ :
          • ใช้ GPU แปลง UI ทั้งหมด
            (ข้อความ, ไอคอน, รูปภาพ, สี, เงา)
            ให้กลายเป็น จุดสีเล็ก ๆ (pixels) ไปแสดงภาพบนหน้าจอ
          • ==📌ถ้าสีนี้สูง → มักเกิดจาก: ออกแบบ UI มีความซับซ้อนจนเกินไป==
        • 🟢 -> 🟥 Jank

          • frame ที่ใช้เวลานานเกินไป → จนทำให้ App กระตุก
          • เกิดเมื่อ UI + Raster รวมกันเกิน 16.7 ms
      • 🟠 FPS = 43 FPS (avg) หมายถึงอะไร

        • ค่าเฉลี่ย Framerate = 43 เฟรมต่อวินาที
        • น้อยกว่า 60 → App เริ่มจะกระตุก
      • 🟠 เส้น 16.7 ms (เส้นอ้างอิง)

        • ถ้าแท่งสูงเกินเส้นนี้ → เฟรมหลุด → กระตุก
      • 🌸 Frame Analysis

        • ใช้วิเคราะห์ความลื่นไหลของการแสดงผลหน้าจอ (FPS / Jank)
        • ดูอะไรได้บ้าง:
          • เวลา render แต่ละ frame

          • แยกเป็น:

            • UI thread → build / layout
            • Raster thread → วาดภาพ
          • หา frame ที่เกิน 16.7 ms (60 FPS)

      • 🌸 Timeline Events

        • ดูเหตุการณ์ทั้งหมดที่เกิดขึ้นตามเวลา
      • 🟣 Rebuild Stats

        • ดูว่า widget ไหนถูก rebuild บ่อย
        • 🟣 Count widget builds
          • เมื่อเปิด ✔️ จะนับจำนวนครั้งที่ widget ถูก rebuild
          • ใช้หาตัวต้นเหตุของ Performance Drop
          • 🟣 Widget
            • ชื่อ widget
          • 🟣 Latest frame
            • rebuild ใน frame ล่าสุด
          • 🟣 Latest frame
            • rebuild รวมทั้งหมด
          • ==👉 ถ้า widget rebuild จำนวนครั้ง บ่อยเกินไป = App ทำงานช้า==

⭐ Running a Flutter app on a physical device for testing Flutter Devtools

  • 🟢 สำหรับ Android

    • ต้องเปิดโหมดนักพัฒนา (Developer Options) ก่อน

    • ขั้นตอนที่ 1: เปิด Developer Mode

      • หยิบมือถือ Android เข้าไปที่ Settings (การตั้งค่า)

      • ไปที่ About Phone (เกี่ยวกับโทรศัพท์)

      • ไปที่ Software information (ข้อมูลซอฟต์แวร์)

      • หาคำว่า Build Number (หมายเลขรุ่น)

      • จิ้มที่ Build Number รัวๆ ประมาณ 7 ครั้ง จนกระทั่งมีข้อความขึ้นว่า "You are now a developer!"

    • ขั้นตอนที่ 2: เปิด USB Debugging

      • ในบางมือถือรุ่นใหม่ จะมี Feature เป็น ตัว Block อัตโนมัติ , เพื่อความปลอดภัยของมือถือ จึงทำให้ไม่สามารถ เปิด USB Debuggin ได้
      • ให้ไปทำการ ปิด ตัว Block อัตโนมัติ , โดยไปที่ Security & Privacy (ความปลอดภัยและความเป็นส่วนตัว)

      • หาคำว่า Auto Blocker (ตัวบล๊อคอัตโนมัติ) , แล้วทำการ ปิดทิ้ง

      • กลับไปที่ เมนู Developer mode
      • ทำการ เปิด USB Debugging

      • 💡 กรณีที่ไม่สามารถเปิด USB Debugging
        • สาย USB อาจมีผล: สายชาร์จบางเส้น "ชาร์จไฟได้อย่างเดียว ส่งข้อมูลไม่ได้" ถ้าเสียบแล้วคอมนิ่งสนิท ลองเปลี่ยนสายดูครับ
        • ถอดสาย USB ออกแล้วเสียบใหม่
        • ปรับโหมดการเชื่อมต่อ USB บนมือถือเป็น PTP หรือ MTP , โดยไปที่
        • เปิดเครื่องโทรศัพท์
        • ไปที่ Developer mode
        • เลือก Default USB configuration (การกำหนดค่า USB เริ่มต้น)
        • กดเข้าไปแล้วเลือก MTP (ถ่ายโอนไฟล์) หรือ PTP (ถ่ายโอนรูปภาพ)
    • ขั้นตอนที่ 3 : เชื่อมต่อคอมพิวเตอร์

      • เสียบสาย USB จากมือถือ เข้า คอมพิวเตอร์
      • สำคัญมาก: ที่หน้าจอมือถือจะมี Popup เด้งขึ้นมาถามว่า "Allow USB debugging?" ให้กด Allow (อนุญาต)
    • ขั้นตอนที่ 4 : สั่ง Run จากในคอมพิวเตอร์

      • เมื่อตั้งค่าเสร็จแล้ว ให้กลับมาที่ Android Studio หรือ VS Code ครับ
      • วิธีเช็คว่าคอมมองเห็นมือถือหรือยัง: เปิด Terminal ในโปรเจกต์ แล้วพิมพ์:
      • flutter devices
      • ถ้าสำเร็จ จะมีชื่อมือถือของคุณโผล่ขึ้นมาครับ (เช่น SM A528B หรือ iPhone of ...)

      • Run ผ่าน Terminal :
        • แบบธรรมดา (Debug):

          • flutter run
        • แบบทดสอบ Performance (Profile):

          • flutter run --profile
        • แบบตัวจริง (Release):

          • flutter run --release
        • ทิ้งท้าย , ไม่จำเป็น ต้องเปิด หรือ Download App จาก Play Store ที่เราได้ทำการ Upload ไปยังบน PlayStore , เพื่อมาทดสอบครับ

          • แอปจาก Play Store เป็น Release build
          • ❌ ไม่สามารถเชื่อมต่อ DevTools ได้

⭐ Flutter Inspector

  • เป็นเครื่องมือ , ตรวจสอบและวิเคราะห์โครงสร้าง UI ของ App Flutter แบบ Real-time

  • สามารถดูโครงสร้าง Widget Tree ได้

  • ตรวจสอบว่า widget ไหนซ้อนอยู่กับอะไร

  • Check ขนาด (size), padding, margin, alignment

  • หา layout ที่ล้นจอ / จัดตำแหน่งผิด

  • ใช้ตรวจสอบปัญหา Performance / ความเร็ว (เบื้องต้น)

  • Menu UI/Inspector

    • 🔴 Select widget mode (โหมดเลือก Widget) 🔍

      • เมื่อกดปุ่มนี้ แล้วไปจิ้มที่หน้าจอมือถือตรงส่วนไหนก็ได้ ในโปรแกรม (VS Code/Android Studio) จะกระโดดไปไฮไลท์ Code ของ Widget ตัวนั้นให้ทันที
      • ประโยชน์
        • เอาไว้หาว่า "ปุ่มนี้มันอยู่ไฟล์ไหนนะ?" หรือ "กล่องนี้มันซ้อนอยู่ใน Column ไหน"
    • 🔴 Show implementation widgets

      • ไว้แสดงไส้ในของ Widget
      • ปกติเวลาเราเขียนโค้ด เราจะใช้ Widget สำเร็จรูปที่ Flutter เตรียมมาให้ เช่น Container, Text, หรือ RaisedButton , แต่ในความเป็นจริง "เบื้องหลัง" ของ Widget พวกนี้ มันถูกสร้างขึ้นมาจาก Widget ย่อยๆ อีกหลายตัวประกอบร่างกัน
      • 💡 ตัวอย่างเปรียบเทียบ

        • แบบปกติ (ปิด Show implementation widgets):

          • ใน Tree จะเห็นแค่บรรทัดเดียว: Text
          • ข้อดี: ดูง่าย รู้เรื่องว่าตรงนี้คือข้อความ
        • แบบละเอียด (เปิด Show Implementation widgets):

          • ใน Tree จะเห็นยาวเหยียด: TextRichTextRawGestureDetector_RenderObjectWidget
          • ข้อดี: เห็นการทำงานลึกๆ ว่า Flutter วาดข้อความยังไง
        • 🛠️ จะเปิดใช้ก็ต่อเมื่อ:

          • อยากรู้วิธีการเขียน: อยากศึกษาว่า Flutter เขียน Widget ตัวนี้ขึ้นมายังไง (เพื่อจะไปเขียน Widget เลียนแบบเอง)
          • แก้บั๊กขั้นสูง: เมื่อเกิดปัญหาแปลกๆ ที่แก้ไม่ได้ และสงสัยว่าเป็นที่ตัว Framework ของ Flutter เอง (ซึ่งเกิดขึ้นน้อยมาก)
    • 🔴 Slow animations 🐢

      • ทำให้ Animation ทั้งหมดใน App ช้าลง 5 เท่า
      • ประโยชน์
        • เอาไว้เช็คความเนียนของ Animation ว่ามันขยับถูกทางไหม หรือมีจังหวะไหนกระตุกหรือเปล่า
    • 🔴 Show guidelines (Debug Paint) 📏

      • จะวาดเส้นขอบ, เส้นลูกศร, และแถบสีฟ้า/เขียว ทับลงบนหน้าจอ เพื่อบอกว่า Widget แต่ละตัวมีระยะห่างกันเท่าไร (Margin/Padding)
      • ประโยชน์:
        • ได้ใช้บ่อยมาก! เวลาจัดหน้าจอไม่ตรง หรือเว้นวรรคผิด กดปุ่มนี้จะเห็นเลยว่าใครกินที่เกิน หรือใครเบียดใครอยู่
    • 🔴 Show baselines 📝

      • ขีดเส้นสีเขียวที่ "ฐาน" ของตัวหนังสือ
      • ประโยชน์:
        • เอาไว้ ตรวจสอบ เวลาเราวาง Icon คู่กับ Text แล้วอยากรู้ว่ามันวางอยู่บนระนาบเดียวกันเป๊ะๆ หรือเปล่า
    • 🔴 Highlight repaints 🌈 (ใช้ ตรวจสอบ Performance / ความเร็ว )

      • ทำหน้าที่:
        • เมื่อไหร่ก็ตามที่มีการเปลี่ยนแปลงบนหน้าจอ (เช่น ตัวเลขวิ่ง, สีกระพริบ) มันจะตี "กรอบสี่เหลี่ยมสีรุ้ง" ล้อมรอบจุดนั้น
      • ใช้ทำอะไร
        • ✅ ตรวจสอบปัญหา Performance / ความเร็ว
        • ถ้า กดปุ่มเล็ก ๆ แต่กรอบสีรุ้งดันกระพริบทั้งหน้าจอ
          → แปลว่า repaint เกินจำเป็น ❌
        • ควร repaint แค่ widget ของส่วนที่มีการเปลี่ยนแปลงตรงจุดนั้นๆ
    • 🔴 Highlight oversized images 🖼️ (สำคัญเรื่อง Memory)

      • 👉 ตรวจจับรูปภาพที่ “ใหญ่เกินความจำเป็น” เมื่อถูกแสดงบนหน้าจอ
      • ใช้เพื่อ แก้ปัญหา Performance และ Memory โดยเฉพาะ
      • หน้าที่:
        • ถ้ารูปภาพไหนที่คุณโหลดมา "รูปจริงมีขนาดใหญ่ เช่น 4000×3000 px" แต่เอามาแสดงผลใน "กรอบเล็กนิดเดียว" ภาพนั้นจะถูก กลับหัว (Flip) และกลับสี (Invert) ให้ดูน่าเกลียดทันที
        • ประโยชน์:
          • เตือนสติ! เช่น คุณเอารูป 4K มาใส่ในกรอบ icon เล็กๆ 50x50 pixel มันเปลือง RAM เครื่องมาก ถ้าเห็นภาพกลับหัว ให้ไปลดขนาดรูปก่อนนำมาใช้ครับ
    • สรุปสั้นๆ:

      • ถ้าจะแก้ UI เบี้ยว -> ใช้ Select widget mode คู่กับ Show guidelines
      • ถ้าแอปกระตุก -> ใช้ Highlight repaints กับ Highlight oversized images
      • ถ้า Animation แปลก -> ใช้ Slow animations
    • 🟠 กรอบสีส้ม: Widget Tree (โครงสร้างต้นไม้)

      • หน้าที่:
        • แสดงให้เห็นว่า Widget ตัวไหนเป็น "พ่อ" (Parent) และตัวไหนเป็น "ลูก" (Child) ซ้อนกันอยู่อย่างไร
    • 🟢 กรอบสีเขียว: View Tabs (เมนูเลือกมุมมอง)

      • 🟢 Widget properties:

        • แสดงค่าการตั้งค่าต่างๆ ที่เราเขียนไว้ใน Code เช่น สี, ขนาด, ข้อความ
      • 🟢 Render object:

        • แสดงข้อมูลทางเทคนิคที่ Flutter ใช้คำนวณการวาดภาพบนหน้าจอ (อันนี้จะลึกหน่อย ใช้ตอนแก้บั๊กยากๆ)
      • 🟢 Flex explorer:

        • เป็นเครื่องมือพิเศษที่จะโผล่มาเมื่อเราเลือก Widget ประเภท Row หรือ Column เพื่อช่วยจำลองการจัดวางตำแหน่ง (Alignment) แบบให้เห็นภาพ
    • 🌸 กรอบสีชมพู: View Tabs (เมนูเลือกมุมมอง)

      • 🌸 ส่วนบน (แผนภาพสีฟ้า/เทา): Layout Visualizer
        • แสดง "ขนาดจริง" ของ Widget (กว้าง x สูง)
        • แสดง Padding/Margin (พื้นที่ว่างรอบๆ)
        • ช่วยให้ดูรู้ทันทีว่า Widget นี้กินพื้นที่หน้าจอไปเท่าไหร่ (ในภาพคือ Column กว้าง 409.4 สูง 689.0)
      • 🌸 ส่วนล่าง (ตารางข้อมูล): Properties Table
        • แสดง "ค่าตัวแปร" ทั้งหมดของ Widget นั้น
          • เช่น mainAxisAlignment: start (เริ่มเรียงจากด้านบน), crossAxisAlignment: center (จัดกึ่งกลางแนวนอน)
        • ช่วยให้เราเช็คได้ว่า สิ่งที่เราเขียนโค้ดไป มันแสดงผลออกมาเป็นค่าอะไรกันแน่
  • ศึกษาเพิ่มเติมได้ที่ :

⭐ How to Configure and Deploy an App Manually

  • Add a launcher icon

    • ให้ไปทำการ Download และ ติตตั้ง Library : flutter_launcher_icons

    • แล้วทำการ Config ตามรูปภาพที่ส่งไป :

    • ไปที่ Path :

      • android/app/src/main/AndroidManifest.xml
    • File AndroidManifest.xml คือ :

      • เป็น File กำหนดตัวตนและพฤติกรรมของ App Android
      • ระบบ Android จะอ่าน File นี้ ก่อน Run App เสมอ
      • ใช้บอก Android ว่า:
        • App ชื่ออะไร
        • ใช้ Icon ตัวไหน
        • Activity ไหนเป็นตัวเริ่ม App- ขอ permission อะไร
        • รองรับ feature อะไรบ้าง

    • ให้ทำการแก้ไข android:label= เป็นชื่อ "TaskFlow" ที่ App เราเคยสร้าง

    • ให้ไปที่ Path :

      • android/app/build.gradle.kts
    • File build.gradle.kts คือ :

      • 👉 เป็น File ตั้งค่าการ Build Project Android ที่เขียนด้วยภาษา Kotlin
      • 👉 App จะถูก build ยังไง ใช้ Android เวอร์ชันไหน ใช้แพ็กเกจอะไรบ้าง

      • ทำการแก้ไขตาม File ภาพ :
        • คำสั่ง namespace = "com.suporn.todolist" ✅ ใช้สำหรับสร้าง Code ใน Andriod
        • คำสั่ง applicationId = "com.suporn.todolist ✅ ใช้สำหรับ ตัว App , ในการ Upload App ไปยัง Playstore

    • คำสั่ง minSdk = flutter.minSdkVersion

      • minSdk = Minimum SDK Version คือ version Android ต่ำสุด ที่ App สามารถติดตั้งได้
      • flutter.minSdkVersion = ค่า version Android ต่ำสุด ที่ Flutter ตั้งให้โดยอัตโนมัติ
    • คำสั่ง targetSdk = flutter.targetSdkVersion

      • targetSdk = Target SDK Version คือ ระบุ version Android ใหม่ล่าสุด , ให้สามารถทำงานทดสอบร่วกับ App ได้
      • flutter.targetSdkVersion = ค่า version Android ใหม่ล่าสุด ที่ Flutter ตั้งให้โดย
    • คำสั่ง targetSdk = flutter.targetSdkVersion

    • คำสั่ง versionName

      • เป็น ชื่อเวอร์ชันที่ผู้ใช้เห็น
      • เป็น string
      • แสดงใน Play Store และหน้า About
    • ไปที่ Path :

      • android/app/src/main/kotlin/com/example/todolist/MainActivity.kt
    • File MainActivity.kt คือ :

      • ✅ File นี้ , ทำหน้าที่เป็น สะพานเชื่อม Flutter ↔ Android

      • ให้ทำการแก้ไข ตาม File ภาพ
      • ✅ namespace ใน file build.gradle.kts กับ package ชื่อควรตรงกัน
    • ไปที่ Path :

      • android/app/google-services.json

      • package_name ใน file : google-services.json , ชื่อต้องตรงกับ package_name ใน build.gradle.ktsและ ต้องตรงกับใน Firebase
      • ถ้าไม่ตรง จะเกิด ❌
        • Firebase เชื่อมต่อไม่ติด
        • App จะใช้งานไม่ได้
  • Create an Upload keystore

    • ให้ทำการสร้าง File key.properties ไว้ใน Path :

      • android\key.properties
    • แล้วทำการ Copy คำสั่ง ไปไว้ใน File key.properties :

       		storePassword=<password-from-previous-step>
       		keyPassword=<password-from-previous-step>
       		keyAlias=upload
       		storeFile=<keystore-file-location>
    • ทำการตั้ง Password ใน :

      • storePassword
      • keyPassword
    • ทำการเปิด Terminal ใน VS code หรือ Android Studio ขึ้นมา

    • แล้ว Run คำสั่ง ตามนี้ :

       	& "C:\Program Files\Android\Android Studio\jbr\bin\keytool.exe" -genkey -v `
       	-keystore $env:USERPROFILE\upload-keystore.jks `
       	-storetype JKS -keyalg RSA -keysize 2048 -validity 10000 `
       	-alias upload
    • ให้เรียกแบบ ระบุ path ตรง ๆ ใน PowerShell แบบนี้ครับ

      • keytool เป็นเครื่องมือที่มากับ JDK (Java Development Kit)
      • แต่เราใช้ JDK ที่มาจาก Android Studio
    • หมายเหตุสำคัญ

      • ต้องมี & นำหน้า (PowerShell ใช้เรียกไฟล์ .exe)
      • เครื่องหมาย ` คือขึ้นบรรทัดใหม่ใน PowerShell
    • จากนั้น มันจะถามหา keyPassword ใน file key.properties , ให้ทำการใส่รหัสผ่านลงไป

    • ระบบ สร้าง keystore สำเร็จแล้ว

      • File ถูกบันทึกที่ - C:\Users\John\upload-keystore.jks
    • เมื่อได้ File upload-keystore.jks มาแล้ว , ให้ทำการย้าย File upload-keystore.jks ไปไว้ Path :

      • android\app\upload-keystore.jks
    • แล้วทำการเปิด File key.properties ขึ้นมาอีกครั้ง

    • ไปแก้ไขตรงคำสั่ง ตรง storeFile= ให้เป็น ../app/upload-keystore.jks
  • Configure signing in Gradle

    • ไปที่ Path :

      • android/app/build.gradle.kts
    • ทำการ Import Library ด้วยคำสั่ง :

       import java.util.Properties
       import java.io.FileInputStream
      • import java.util.Properties

        • ใช้สำหรับ อ่านไฟล์ .properties เช่น key.properties
        • เก็บข้อมูลแบบ key=value
      • import java.io.FileInputStream

        • ใช้ เปิด File จริง ในพื้นที่ local บนเครื่องคอมเรา
        • FileInputStream = อ่านข้อมูลจากไฟล์
        • ใช้เปิด key.properties เพื่อส่งให้ Properties.load()
    • เขียนคำสั่ง อ่าน File key.properties , เพื่อนำข้อมูลไปใช้ Signing Android

       		val keystoreProperties = Properties()        //✅ เตรียมตัวแปรไว้เก็บค่าจากไฟล์
       		val key.propertiesval keystorePropertiesFile = rootProject.file("key.properties")    
       		if (keystorePropertiesFile.exists()) {  
       		    keystoreProperties.load(FileInputStream(keystorePropertiesFile))  
       		}
    • กำหนดข้อมูลการ (Signing Configuration) สำหรับ Build แบบ Release

       	signingConfigs {  
      
       	  create("release") { //✅  สร้าง config ชื่อ release 
       	  //📌 ค่าทั้งหมดมาจาก key.properties  
       			  keyAlias = keystoreProperties["keyAlias"] as String  
       		      keyPassword = keystoreProperties["keyPassword"] as String  
       		      storeFile = keystoreProperties["storeFile"]?.let { file(it) }  
       			  storePassword = keystoreProperties["storePassword"] as String  
       	    }  
       	}
    • เพิ่มคำสั่ง สำหรับ ปล่อย App ตัวจริง

      	buildTypes {  
      	  release {  
      	  // TODO: Add your own signing config for the release build.  
      	  // Signing with the debug keys for now, so `flutter run --release` works.  
      		 //📌 บรรทัดแรก (debug) → ใช้แค่ชั่วคราว / ตัวอย่าง  
      		  //signingConfig = signingConfigs.getByName("debug")  
      		 //📌 บรรทัดที่สอง (release) → ใช้สำหรับปล่อย App ตัวจริง  
      		  signingConfig = signingConfigs.getByName("release")  
      		    }  
      		}
    • จากนั้นเปิด Terminal ขึ้นมา , แล้วใช้คำสั่งตามนี้

      flutter build appbundle --release

    • เป็นคำสั่งสำหรับ

      • 👉 สร้างไฟล์ Android App Bundle (.aab)
      • 👉 ในโหมด Release
    • ใช้ทำอะไร

      • ไฟล์ .aab คือไฟล์ที่ Google Play Store ต้องการ
      • ใช้สำหรับ อัปโหลดแอปขึ้น Play Store
    • ศึกษาเพิ่มเติมได้ที่ :

🚨 How to fix Gradle build errors

  • วิธีแก้ไข , กรณี Error เวลา Build ด้วย Gradle: ถูกล็อก (file locking)** หรือ cache ของ Gradle เสีย/ค้าง
  • หากใช้คำสั่ง flutter run แล้วเกิด Error ลักษณะแบบนี้

Suppressed: java.lang.Exception: Storage[...] registration stack trace java.lang.IllegalStateException: Storage for [...] is already registered

  • หรือ

java.lang.AssertionError: Could not delete caches dir yourProject\build\kotlin\compileDebugTestingKotlin

วิธีแก้ไข

  • หยุด Gradle Daemon

    • ไปที่ Folder android
    • ใช้คำสั่งตามนี้
    • cd android
    • ./gradlew --stop
    • หรือจะ Run ด้วยคำสั่ง ./gradlew clean
  • ปิด Java Process

    • เปิด Task Manager
    • ปิด process ที่ชื่อ java.exe ทั้งหมด
  • ลบ Folder .gradle ออก

    • เข้าไปที่ Folder android
    • หาชื่อ Folder .gradle , แล้วทำการลบทิ้ง เพื่อเคลียร์ cache ของ Gradle เสีย/ค้าง ออกไปให้หมด
  • Invalidate Caches และ Restart IDE

    • เปิด Android Studio
    • ไปที่เมนู File > Invalidate Caches...
    • ติ๊กช่อง (โดยเฉพาะ Clear file system cache and Local History)
    • กด Invalidate and Restart
  • ลองใช้คำสั่ง flutter run อีกรอบ

    • cd ..
    • flutter clean
    • flutter pub get
    • flutter run
  • หากเกิด Error แบบนี้ :

    Suppressed: java.lang.IllegalArgumentException: this and base files have different roots:

    • วิธีแก้ไข กรณีที่ 1

      1. ใช้คำสั่ง flutter clean , ลบไฟล์ build และ cache เก่าทั้งหมดของ Flutter
      2. เปิด Folder android/ใน File Project เรา , ด้วย Android Studio
      3. ให้ Android Studio ทำ Gradle Sync , - 👉 ยังไม่ต้อง รัน flutter pub get
      4. เปิดเมนู File ใน Android Studio , แล้วเลือก Sync Project with Gradle Files
      • เหตุผล - บางปัญหาเกิดจากฝั่ง Android โดยตรง
      1. กลับมาที่ root ของ Flutter project , โดยใช้คำสั่ง cd ..

      2. Run คำสั่ง:

          - flutter pub get
          - flutter run
        

        ผลลัพธ์ : ดึง package ใหม่ทั้งหมด , - build App ใหม่ด้วย environment ที่สะอาดแล้ว

    • วิธีแก้ไข กรณีที่ 2

      • แก้ปัญหา build / Gradle / Flutter error ได้ โดยการย้าย Folder Project ไปไว้ใน Drive เดียวกัน
        • ก่อนหน้า

            -  Project อยู่ที่
            	    -	D:\my_flutter_project` 
          
        • แต่ Android SDK / Java / Gradle / Flutter
          ส่วนใหญ่อยู่ใน

          - C:\ (เช่น C:\Android\Sdk)` 
          
        • ปัญหาที่เกิด

          • Gradle / Kotlin daemon มีปัญหาเรื่อง - file lock - cache - incremental build
          • โดยเฉพาะบน Windows
            เมื่อโปรเจกต์อยู่คนละ drive กับ SDK
        • วิธีแก้

          • ย้ายโปรเจกต์จาก D:C:
            - เช่น:

            C:\Projects\my_flutter_project`

        • จากนั้น build ใหม่

        • flutter clean
        • flutter run

🚨 How to fix the launcher icon image not changing to the new image

  • วิธีแก้ไข

    1. เปิด Android Studio ขึ้นมา
    2. ไปที่ Folder Project เรา , แล้วไปตาม path : android/app/src/main/res
    3. จากนั้นให้ลบ File ตาม ภาพนี้

	-   จากนั้น build ใหม่
		> - flutter clean
		> - flutter run

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published