ใใใใใขใใชใฑใผใทใงใณใฏใFlutter MVCใขใผใญใใฏใใฃใใฟใผใณใๆก็จใใไฟๅฎๆงใจๆกๅผตๆงใ้่ฆใใ่จญ่จใจใชใฃใฆใใพใใ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Presentation Layer โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โ โ Views โ โ Dialogs โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Application Layer โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โ โ Controllers โ โ Services โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Domain Layer โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โ โ Models โ โ Entities โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Infrastructure Layer โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โ โ Storage โ โ External โ โ
โ โ โ โ Services โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ็ป้ขใณใณใใผใใณใ
- YaruKotoListView // ใใญใธใงใฏใไธ่ฆง็ป้ข
- YaruKotoDetailView // ใใญใธใงใฏใ่ฉณ็ดฐ็ป้ข๏ผ้
็ฎไธ่ฆง๏ผ
- TaskItemDetailView // ้
็ฎ่ฉณ็ดฐ็ป้ข๏ผใฟในใฏไธ่ฆง๏ผ
- SettingsView // ่จญๅฎ็ป้ข
// ใใคใขใญใฐใณใณใใผใใณใ
- AddYaruKotoDialog // ใใญใธใงใฏใ่ฟฝๅ ใใคใขใญใฐ
- EditYaruKotoDialog // ใใญใธใงใฏใ็ทจ้ใใคใขใญใฐ
- AddTaskItemDialog // ้
็ฎ่ฟฝๅ ใใคใขใญใฐ
- EditTaskItemDialog // ้
็ฎ็ทจ้ใใคใขใญใฐ
- AddTaskDialog // ใฟในใฏ่ฟฝๅ ใใคใขใญใฐ
- EditTaskDialog // ใฟในใฏ็ทจ้ใใคใขใญใฐ
// ็ถๆ
็ฎก็ใปใใธใในใญใธใใฏๅถๅพก
YaruKotoController extends ChangeNotifier {
- List<YaruKoto> _yaruKotoList
- bool _isLoading
// ใใญใธใงใฏใๆไฝ
+ addYaruKoto(String title, String? description)
+ updateYaruKoto(String id, String? title, String? description)
+ deleteYaruKoto(String id)
+ reorderYaruKoto(int oldIndex, int newIndex)
// ้
็ฎๆไฝ๏ผไธญ้้ๅฑค๏ผ
+ addTaskItem(String yaruKotoId, String itemTitle, String? description)
+ updateTaskItem(String yaruKotoId, String taskItemId, String? title, String? description)
+ deleteTaskItem(String yaruKotoId, String taskItemId)
+ reorderTaskItems(String yaruKotoId, int oldIndex, int newIndex)
// ใฟในใฏๆไฝ๏ผๆๅฐๅไฝ๏ผ
+ addTask(String yaruKotoId, String taskItemId, String taskTitle)
+ updateTask(String yaruKotoId, String taskItemId, String taskId, String newTitle)
+ updateTaskProgress(String yaruKotoId, String taskItemId, String taskId, TaskProgress progress)
+ nextTaskProgress(String yaruKotoId, String taskItemId, String taskId)
+ deleteTask(String yaruKotoId, String taskItemId, String taskId)
+ reorderTasks(String yaruKotoId, String taskItemId, int oldIndex, int newIndex)
}
// ๅค้จใตใผใในใจใฎ้ฃๆบ
YaruKotoService {
+ getAllYaruKoto(): Future<List<YaruKoto>>
+ saveYaruKoto(List<YaruKoto> list): Future<void>
+ addYaruKoto(YaruKoto yaruKoto): Future<void>
+ updateYaruKoto(YaruKoto yaruKoto): Future<void>
+ deleteYaruKoto(String id): Future<void>
}
AdMobService {
+ initialize(): Future<void>
+ loadBannerAd(): BannerAd
+ loadInterstitialAd(): InterstitialAd
}
// ใใธใในใใกใคใณใฎใจใณใใฃใใฃ
class YaruKoto {
final String id;
final String title;
final String? description;
final List<TaskItem> items;
final DateTime createdAt;
double get progressPercentage; // ้
็ฎใฎๅนณๅๅค
String get progressLabel;
}
class TaskItem {
final String id;
final String title;
final String? description;
final List<Task> tasks;
final DateTime createdAt;
double get progressPercentage; // ใฟในใฏใฎๅนณๅๅค
String get progressLabel;
}
class Task {
final String id;
final String title;
final TaskProgress progress;
final DateTime createdAt;
}
enum TaskProgress {
notStarted(0, 'ๆช็ๆ'),
inProgress(50, 'ใกใใฃใจใใฃใ'),
completed(100, 'ๅฎไบ');
}
// ใใผใฟๆฐธ็ถๅ
SharedPreferences {
+ getString(String key): String?
+ setString(String key, String value): Future<bool>
}
// ๅค้จใตใผใใน
GoogleMobileAds {
+ initialize(): Future<void>
+ BannerAd
+ InterstitialAd
+ NativeAd
}
User Action โ View โ Controller โ Service โ Model โ Controller โ View
Controller โ Service โ SharedPreferences โ JSON Storage
App Start โ Controller.loadData() โ Service.getAllYaruKoto() โ SharedPreferences โ JSON Parse โ Model List
// main.dart
ChangeNotifierProvider(
create: (context) => YaruKotoController(),
child: MyApp(),
)
// View
Consumer<YaruKotoController>(
builder: (context, controller, child) {
return ListView.builder(
itemCount: controller.yaruKotoList.length,
itemBuilder: (context, index) {
return YaruKotoCard(controller.yaruKotoList[index]);
},
);
},
)
// ๆฐใใใตใผใในใฎ่ฟฝๅ
abstract class StatisticsService {
Future<Statistics> getStatistics();
}
class StatisticsServiceImpl implements StatisticsService {
@override
Future<Statistics> getStatistics() async {
// ๅฎ่ฃ
}
}
// ๆฝ่ฑกๅใซใใในใใฌใผใธๅคๆดใๅฎนๆ
abstract class StorageService {
Future<List<YaruKoto>> getAllYaruKoto();
Future<void> saveYaruKoto(List<YaruKoto> list);
}
class SharedPreferencesStorage implements StorageService {
// SharedPreferencesๅฎ่ฃ
}
class SqliteStorage implements StorageService {
// SQLiteๅฎ่ฃ
}
// ใขใใซใฎใในใ
test('YaruKoto progress calculation', () {
final yaruKoto = YaruKoto(
id: '1',
title: 'Test Project',
items: [
TaskItem(id: '1', title: 'Task 1', progress: TaskProgress.completed),
TaskItem(id: '2', title: 'Task 2', progress: TaskProgress.inProgress),
],
createdAt: DateTime.now(),
);
expect(yaruKoto.progressPercentage, 75.0);
});
// Controller + Service ใฎใในใ
testWidgets('Add YaruKoto integration test', (tester) async {
final controller = YaruKotoController();
await controller.addYaruKoto('Test Project');
expect(controller.yaruKotoList.length, 1);
expect(controller.yaruKotoList.first.title, 'Test Project');
});
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return YaruKotoCard(key: ValueKey(items[index].id), item: items[index]);
},
)
// ๅฟ
่ฆใช้จๅใฎใฟๆดๆฐ
Consumer<YaruKotoController>(
builder: (context, controller, child) {
return Text(controller.yaruKotoList.length.toString());
},
)
ใใฎ่จญ่จใซใใใไฟๅฎๆงใ้ซใใๆกๅผตใใใใใขใใชใฑใผใทใงใณใๅฎ็พใใฆใใพใใ