feat(knowledge): update Project model, ProjectsApi sort, and NoteEditScreen noteType support

This commit is contained in:
2026-04-04 23:52:10 -04:00
parent f5ba2d25a3
commit a50193dbc0
4 changed files with 40 additions and 4 deletions
+7 -1
View File
@@ -11,7 +11,11 @@ class ProjectsApi {
try { try {
final response = await _dio.get( final response = await _dio.get(
'/api/projects', '/api/projects',
queryParameters: status != null ? {'status': status} : null, queryParameters: {
'sort': 'updated_at',
'order': 'desc',
if (status != null) 'status': status,
},
); );
final data = response.data as Map<String, dynamic>; final data = response.data as Map<String, dynamic>;
final list = data['projects'] as List<dynamic>; final list = data['projects'] as List<dynamic>;
@@ -37,10 +41,12 @@ class ProjectsApi {
String? description, String? description,
String? goal, String? goal,
String? color, String? color,
String status = 'active',
}) async { }) async {
try { try {
final response = await _dio.post('/api/projects', data: { final response = await _dio.post('/api/projects', data: {
'title': title, 'title': title,
'status': status,
if (description != null && description.isNotEmpty) if (description != null && description.isNotEmpty)
'description': description, 'description': description,
if (goal != null && goal.isNotEmpty) 'goal': goal, if (goal != null && goal.isNotEmpty) 'goal': goal,
+4
View File
@@ -5,6 +5,7 @@ class Project {
final String? goal; final String? goal;
final String status; // active | completed | archived final String status; // active | completed | archived
final String? color; final String? color;
final String? autoSummary;
final DateTime createdAt; final DateTime createdAt;
final DateTime updatedAt; final DateTime updatedAt;
@@ -15,6 +16,7 @@ class Project {
this.goal, this.goal,
required this.status, required this.status,
this.color, this.color,
this.autoSummary,
required this.createdAt, required this.createdAt,
required this.updatedAt, required this.updatedAt,
}); });
@@ -26,6 +28,7 @@ class Project {
goal: json['goal'] as String?, goal: json['goal'] as String?,
status: json['status'] as String? ?? 'active', status: json['status'] as String? ?? 'active',
color: json['color'] as String?, color: json['color'] as String?,
autoSummary: json['auto_summary'] as String?,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
); );
@@ -36,5 +39,6 @@ class Project {
'goal': goal, 'goal': goal,
'status': status, 'status': status,
'color': color, 'color': color,
'auto_summary': autoSummary,
}; };
} }
@@ -12,9 +12,14 @@ class ProjectsRepository {
String? description, String? description,
String? goal, String? goal,
String? color, String? color,
String status = 'active',
}) => }) =>
_api.create( _api.create(
title: title, description: description, goal: goal, color: color); title: title,
description: description,
goal: goal,
color: color,
status: status);
Future<Project> update(int id, Map<String, dynamic> fields) => Future<Project> update(int id, Map<String, dynamic> fields) =>
_api.update(id, fields); _api.update(id, fields);
Future<void> delete(int id) => _api.delete(id); Future<void> delete(int id) => _api.delete(id);
+23 -2
View File
@@ -11,7 +11,8 @@ import '../../widgets/project_selector.dart';
class NoteEditScreen extends ConsumerStatefulWidget { class NoteEditScreen extends ConsumerStatefulWidget {
final int? noteId; final int? noteId;
const NoteEditScreen({super.key, this.noteId}); final String? noteType; // passed when creating a typed note from KnowledgeScreen
const NoteEditScreen({super.key, this.noteId, this.noteType});
@override @override
ConsumerState<NoteEditScreen> createState() => _NoteEditScreenState(); ConsumerState<NoteEditScreen> createState() => _NoteEditScreenState();
@@ -25,12 +26,14 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
int? _projectId; int? _projectId;
bool _preview = false; bool _preview = false;
bool _saving = false; bool _saving = false;
late String _noteType;
late final Future<void> _initFuture; late final Future<void> _initFuture;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_noteType = widget.noteType ?? 'note';
_initFuture = _initFuture =
widget.noteId != null ? _loadExisting() : Future.value(); widget.noteId != null ? _loadExisting() : Future.value();
} }
@@ -50,6 +53,7 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
_contentController.text = note.body; _contentController.text = note.body;
_tags = List<String>.from(note.tags); _tags = List<String>.from(note.tags);
_projectId = note.projectId; _projectId = note.projectId;
_noteType = note.noteType;
} }
void _addTag(String raw) { void _addTag(String raw) {
@@ -108,6 +112,7 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
body, body,
tags: _tags, tags: _tags,
projectId: _projectId, projectId: _projectId,
noteType: _noteType,
); );
if (mounted) context.pop(); if (mounted) context.pop();
} else { } else {
@@ -118,6 +123,7 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
tags: _tags, tags: _tags,
projectId: _projectId, projectId: _projectId,
clearProject: _projectId == null, clearProject: _projectId == null,
noteType: _noteType,
); );
if (mounted) context.pop(); if (mounted) context.pop();
} }
@@ -138,7 +144,22 @@ class _NoteEditScreenState extends ConsumerState<NoteEditScreen> {
builder: (context, snapshot) { builder: (context, snapshot) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(widget.noteId == null ? 'New Note' : 'Edit Note'), title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(widget.noteId == null ? 'New Note' : 'Edit Note'),
if (_noteType != 'note')
Chip(
label: Text(
_noteType,
style: const TextStyle(fontSize: 11),
),
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
],
),
actions: [ actions: [
if (widget.noteId != null) if (widget.noteId != null)
IconButton( IconButton(