Expense Tracker App

แอปจัดการรายจ่ายจากคอร์ส Flutter Academind Section 5-6 — เป็นแอปแรกที่ประกอบ concept หลายตัวเข้าด้วยกัน

Repo: flutter-expense-tracker-app

Widget Tree

graph TD
  MaterialApp --> Scaffold
  Scaffold --> AppBar["AppBar + IconButton"]
  Scaffold --> Column
  Column --> Chart["Chart (FractionallySizedBox)"]
  Column --> ExpensesList["ExpensesList (ListView.builder)"]
  ExpensesList --> Dismissible["Dismissible + ValueKey"]
  Dismissible --> ExpenseItem
  ExpenseItem --> Card
  Card --> Row
  Row --> ColLeft["Column (title + date)"]
  Row --> Spacer
  Row --> RowRight["Row (icon + amount)"]

สิ่งที่เรียนจาก Section 5

UI & Layout

  • AppBar + actions — แถบบน + ปุ่ม IconButton เปิด modal
  • Card + Padding + Row + Spacer — layout ของแต่ละ expense item
  • ListView.builder — สร้าง item เฉพาะที่เห็นบนจอ ประหยัด memory (ต่างจาก Column ที่สร้างทุกตัว)
  • Stack — ซ้อน widget ทับกัน

State Management

  • StatefulWidget — จัดการ _registeredExpenses list
  • setState() — บอก Flutter ให้ rebuild UI เมื่อ list เปลี่ยน

User Input

  • TextEditingController + dispose() — จัดการ input title/amount (ต้อง dispose ไม่งั้น memory leak)
  • DropdownButton — เลือกหมวดหมู่ expense
  • showDatePicker + async/await — เลือกวันที่
  • Validationdouble.tryParse(), .trim(), .isEmpty, logical operators (||, &&)

Dialogs & Overlays

  • showModalBottomSheet — ฟอร์มเพิ่ม expense (เปิดจากด้านล่าง)
  • showDialog + AlertDialog — แจ้ง validation error
  • ScaffoldMessenger + SnackBar — แจ้งเตือน + Undo ลบ expense (persist: false)
  • Navigator.pop() — ปิด modal/overlay

Swipe to Delete

  • Dismissible + ValueKey — ปัดลบ item ออกจาก list
  • SnackBar Undo — กดย้อนกลับเพิ่ม item คืนได้

Data Modeling

  • enum Category + categoryIcons map — หมวดหมู่แบบ type-safe
  • Initializer list (:) — auto-generate id ด้วย UUID v4
  • ExpenseBucket + forCategory named constructor — จัดกลุ่มค่าใช้จ่ายสำหรับกราฟ

Chart

  • FractionallySizedBox — bar สูงตามสัดส่วน (0.0–1.0) ของค่าใช้จ่ายสูงสุด
  • ExpenseBucket + totalExpenses getter — คำนวณยอดรวมต่อหมวด

สิ่งที่เรียนจาก Section 5-6 (Theming & Responsive)

Theming

  • ThemeData().copyWith() + ColorScheme.fromSeed() — กำหนด theme ทั้งแอปจากจุดเดียว
  • Dark modeThemeData.dark().copyWith() + kDarkColorScheme
  • MediaQuery — เช็ค platformBrightness สำหรับ dark/light
  • k prefix — convention ตั้งชื่อ global/constant variables (เช่น kColorScheme)
  • CardThemeData — Flutter เวอร์ชันใหม่ใช้แทน CardTheme

Responsive (Section 6)

  • LayoutBuilder — ดู constraints ของ parent เพื่อเลือก layout
  • MediaQuery.of(context).size.width — ดูขนาดจอ
  • SafeArea — หลีก notch/status bar
  • เปลี่ยน Column → Row เมื่อจอกว้างพอ

Key Points

  • แอปแรกที่ประกอบ concept หลายตัว: State, Input, Theme, Layout, Overlay, Validation
  • ListView.builder + Dismissible คือ pattern มาตรฐานสำหรับ swipe-to-delete list
  • TextEditingController ต้อง dispose() เสมอ — ไม่งั้น memory leak
  • ThemeData().copyWith() ตั้ง style จากจุดเดียว ไม่ต้อง hardcode สีทั่วแอป
  • Validation ใช้ tryParse (ไม่ throw) + logical operators รวมเงื่อนไข
  • FractionallySizedBox ใช้สัดส่วน 0.0–1.0 แทนค่า pixel ตายตัว
  • Flutter — framework ที่ใช้สร้างแอปนี้
  • Widgets — reference ของทุก widget ที่ใช้
  • Dart — ภาษาที่เขียน (enum, initializer list, async/await, tryParse)
  • UUID — ใช้ v4 สร้าง unique ID
  • Responsive Design — Section 6 ปรับ layout ตามขนาดจอ
  • Flutter Academind Complete — สรุปคอร์สทั้งหมด