AI Subject, Description and Action taken support

This commit is contained in:
2026-03-04 00:38:35 +08:00
parent b5449f7842
commit c123c09233
4 changed files with 205 additions and 142 deletions
+78 -40
View File
@@ -1,4 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:tasq/utils/app_time.dart';
@@ -582,6 +585,9 @@ class _TasksListScreenState extends ConsumerState<TasksListScreen>
String? requestTypeOther;
String? selectedRequestCategory;
var showTitleGemini = false;
Timer? titleTypingTimer;
await showDialog<void>(
context: context,
builder: (dialogContext) {
@@ -607,52 +613,84 @@ class _TasksListScreenState extends ConsumerState<TasksListScreen>
child: GeminiAnimatedBorder(
isProcessing: titleProcessing,
useDeepSeekColors: titleDeepSeek,
child: TypeAheadFormField<String>(
textFieldConfiguration: TextFieldConfiguration(
controller: titleController,
decoration: const InputDecoration(
labelText: 'Task title',
),
enabled: !saving,
),
suggestionsCallback: (pattern) async {
return SubjectSuggestionEngine.suggest(
existingSubjects: existingSubjects,
query: pattern,
limit: 8,
child: KeyboardListener(
focusNode: FocusNode(),
onKeyEvent: (event) {
if (event is! KeyDownEvent &&
event is! KeyRepeatEvent) {
return;
}
if (event.character == null ||
event.character!.isEmpty) {
return;
}
titleTypingTimer?.cancel();
if (showTitleGemini) {
setState(() => showTitleGemini = false);
}
titleTypingTimer = Timer(
const Duration(milliseconds: 700),
() {
if (titleController.text
.trim()
.isNotEmpty) {
setState(() => showTitleGemini = true);
}
},
);
},
itemBuilder: (context, suggestion) => ListTile(
dense: true,
title: Text(suggestion),
),
onSuggestionSelected: (suggestion) {
titleController
..text = suggestion
..selection = TextSelection.collapsed(
offset: suggestion.length,
child: TypeAheadFormField<String>(
textFieldConfiguration: TextFieldConfiguration(
controller: titleController,
decoration: const InputDecoration(
labelText: 'Task title',
),
enabled: !saving,
),
suggestionsCallback: (pattern) async {
return SubjectSuggestionEngine.suggest(
existingSubjects: existingSubjects,
query: pattern,
limit: 8,
);
},
},
itemBuilder: (context, suggestion) => ListTile(
dense: true,
title: Text(suggestion),
),
onSuggestionSelected: (suggestion) {
titleTypingTimer?.cancel();
titleController
..text = suggestion
..selection = TextSelection.collapsed(
offset: suggestion.length,
);
setState(() => showTitleGemini = false);
},
),
),
),
),
GeminiButton(
textController: titleController,
onTextUpdated: (updatedText) {
setState(() {
titleController.text = updatedText;
});
},
onProcessingStateChanged: (isProcessing) {
setState(() {
titleProcessing = isProcessing;
});
},
onProviderChanged: (isDeepSeek) {
setState(() => titleDeepSeek = isDeepSeek);
},
tooltip: 'Improve task title with Gemini',
),
if (showTitleGemini)
GeminiButton(
textController: titleController,
onTextUpdated: (updatedText) {
titleTypingTimer?.cancel();
setState(() {
titleController.text = updatedText;
showTitleGemini = false;
});
},
onProcessingStateChanged: (isProcessing) {
setState(() {
titleProcessing = isProcessing;
});
},
onProviderChanged: (isDeepSeek) {
setState(() => titleDeepSeek = isDeepSeek);
},
tooltip: 'Improve task title with Gemini',
),
],
),
const SizedBox(height: 12),