diff --git a/lib/data/api/knowledge_api.dart b/lib/data/api/knowledge_api.dart new file mode 100644 index 0000000..71e84f7 --- /dev/null +++ b/lib/data/api/knowledge_api.dart @@ -0,0 +1,86 @@ +import 'package:dio/dio.dart'; + +import '../models/knowledge_item.dart'; +import 'api_client.dart'; + +class KnowledgeApi { + final Dio _dio; + const KnowledgeApi(this._dio); + + /// Fetch a page of IDs. Returns (ids, total). + Future<(List, int)> fetchIds({ + String? noteType, + List tags = const [], + String sort = 'modified', + String? q, + int limit = 50, + int offset = 0, + }) async { + try { + final params = { + 'limit': limit, + 'offset': offset, + 'sort': sort, + if (noteType != null) 'type': noteType, + if (tags.isNotEmpty) 'tags': tags.join(','), + if (q != null && q.isNotEmpty) 'q': q, + }; + final response = + await _dio.get('/api/knowledge/ids', queryParameters: params); + final data = response.data as Map; + final ids = + (data['ids'] as List).map((e) => e as int).toList(); + final total = data['total'] as int; + return (ids, total); + } on DioException catch (e) { + throw dioToApp(e); + } + } + + /// Batch-hydrate up to 100 IDs into full items. + Future> fetchBatch(List ids) async { + if (ids.isEmpty) return []; + try { + final response = await _dio.get( + '/api/knowledge/batch', + queryParameters: {'ids': ids.join(',')}, + ); + final data = response.data as Map; + return (data['items'] as List) + .map((e) => KnowledgeItem.fromJson(e as Map)) + .toList(); + } on DioException catch (e) { + throw dioToApp(e); + } + } + + /// Per-type counts for tab labels. + Future> fetchCounts({List tags = const []}) async { + try { + final params = { + if (tags.isNotEmpty) 'tags': tags.join(','), + }; + final response = await _dio.get('/api/knowledge/counts', + queryParameters: params); + return (response.data as Map) + .map((k, v) => MapEntry(k, (v as num).toInt())); + } on DioException catch (e) { + throw dioToApp(e); + } + } + + /// All tags for the current type filter. + Future> fetchTags({String? noteType}) async { + try { + final response = await _dio.get( + '/api/knowledge/tags', + queryParameters: {if (noteType != null) 'type': noteType}, + ); + return (response.data['tags'] as List) + .map((e) => e as String) + .toList(); + } on DioException catch (e) { + throw dioToApp(e); + } + } +} diff --git a/lib/data/repositories/knowledge_repository.dart b/lib/data/repositories/knowledge_repository.dart new file mode 100644 index 0000000..f6264ac --- /dev/null +++ b/lib/data/repositories/knowledge_repository.dart @@ -0,0 +1,33 @@ +import '../api/knowledge_api.dart'; +import '../models/knowledge_item.dart'; + +class KnowledgeRepository { + final KnowledgeApi _api; + const KnowledgeRepository(this._api); + + Future<(List, int)> fetchIds({ + String? noteType, + List tags = const [], + String sort = 'modified', + String? q, + int limit = 50, + int offset = 0, + }) => + _api.fetchIds( + noteType: noteType, + tags: tags, + sort: sort, + q: q, + limit: limit, + offset: offset, + ); + + Future> fetchBatch(List ids) => + _api.fetchBatch(ids); + + Future> fetchCounts({List tags = const []}) => + _api.fetchCounts(tags: tags); + + Future> fetchTags({String? noteType}) => + _api.fetchTags(noteType: noteType); +} diff --git a/lib/providers/api_client_provider.dart b/lib/providers/api_client_provider.dart index 2aba0ce..7ae55e2 100644 --- a/lib/providers/api_client_provider.dart +++ b/lib/providers/api_client_provider.dart @@ -6,6 +6,7 @@ import '../data/api/api_client.dart'; import '../data/api/auth_api.dart'; import '../data/api/briefing_api.dart'; import '../data/api/chat_api.dart'; +import '../data/api/knowledge_api.dart'; import '../data/api/milestones_api.dart'; import '../data/api/notes_api.dart'; import '../data/api/projects_api.dart'; @@ -14,6 +15,7 @@ import '../data/api/settings_api.dart'; import '../data/api/tasks_api.dart'; import '../data/repositories/auth_repository.dart'; import '../data/repositories/chat_repository.dart'; +import '../data/repositories/knowledge_repository.dart'; import '../data/repositories/milestones_repository.dart'; import '../data/repositories/notes_repository.dart'; import '../data/repositories/projects_repository.dart'; @@ -83,6 +85,14 @@ final milestonesRepositoryProvider = Provider((ref) { return MilestonesRepository(ref.watch(milestonesApiProvider)); }); +final knowledgeApiProvider = Provider((ref) { + return KnowledgeApi(ref.watch(dioProvider)); +}); + +final knowledgeRepositoryProvider = Provider((ref) { + return KnowledgeRepository(ref.watch(knowledgeApiProvider)); +}); + final briefingApiProvider = Provider((ref) { return BriefingApi(ref.watch(dioProvider)); });