feat: 重构会话管理与提醒通知系统

This commit is contained in:
qzl
2026-03-31 18:26:36 +08:00
parent a8c262e9c7
commit 9a231dae9e
31 changed files with 650 additions and 223 deletions
@@ -52,6 +52,7 @@ class HomeScreen extends StatefulWidget {
final VoiceRecorder? voiceRecorder;
final Future<String> Function(String filePath)? onTranscribeAudio;
final ChatBloc? chatBloc;
final String? initialUserId;
final bool autoLoadHistory;
final List<XFile> initialSelectedImages;
@@ -60,6 +61,7 @@ class HomeScreen extends StatefulWidget {
this.voiceRecorder,
this.onTranscribeAudio,
this.chatBloc,
this.initialUserId,
this.autoLoadHistory = true,
this.initialSelectedImages = const [],
});
@@ -119,7 +121,10 @@ class _HomeScreenState extends State<HomeScreen>
duration: const Duration(milliseconds: _rippleDurationMs),
);
_selectedImages.addAll(widget.initialSelectedImages);
if (widget.autoLoadHistory &&
final initialUserId = widget.initialUserId?.trim();
if (initialUserId != null && initialUserId.isNotEmpty) {
unawaited(_chatBloc.switchUser(initialUserId));
} else if (widget.autoLoadHistory &&
_chatBloc.state.items.isEmpty &&
!_chatBloc.state.isLoadingHistory) {
_chatBloc.loadHistory();
@@ -166,6 +171,20 @@ class _HomeScreenState extends State<HomeScreen>
}
}
@override
void didUpdateWidget(covariant HomeScreen oldWidget) {
super.didUpdateWidget(oldWidget);
final oldUserId = oldWidget.initialUserId?.trim();
final newUserId = widget.initialUserId?.trim();
if (oldUserId == newUserId) {
return;
}
final normalized = (newUserId != null && newUserId.isNotEmpty)
? newUserId
: null;
unawaited(_chatBloc.switchUser(normalized));
}
@override
void didPopNext() {
unawaited(_inboxSyncStore.refreshSnapshot());
@@ -42,14 +42,23 @@ class _TodoQuadrantsScreenState extends State<TodoQuadrantsScreen> {
int newItemIndex,
int newListIndex,
) async {
print(
'DEBUG _onItemReorder: oldItemIndex=$oldItemIndex, oldListIndex=$oldListIndex, newItemIndex=$newItemIndex, newListIndex=$newListIndex',
);
if (_isReordering) {
print('DEBUG _onItemReorder: early return - _isReordering=true');
return;
}
final sourceQuadrant = _quadrantByListIndex(oldListIndex);
final targetQuadrant = _quadrantByListIndex(newListIndex);
print(
'DEBUG _onItemReorder: sourceQuadrant=$sourceQuadrant, targetQuadrant=$targetQuadrant',
);
final sourceItems = _sortedQuadrantTodos(sourceQuadrant);
print('DEBUG _onItemReorder: sourceItems.length=${sourceItems.length}');
if (oldItemIndex < 0 || oldItemIndex >= sourceItems.length) {
print('DEBUG _onItemReorder: early return - index out of bounds');
return;
}
@@ -66,7 +75,9 @@ class _TodoQuadrantsScreenState extends State<TodoQuadrantsScreen> {
targetQuadrant: targetQuadrant,
insertIndex: newItemIndex,
);
print('DEBUG _onItemReorder: reordered=$reordered');
if (reordered == null) {
print('DEBUG _onItemReorder: early return - reordered is null');
return;
}
@@ -117,19 +128,27 @@ class _TodoQuadrantsScreenState extends State<TodoQuadrantsScreen> {
required int targetQuadrant,
required int insertIndex,
}) {
print(
'DEBUG _reorderTodos: todoId=$todoId, sourceQuadrant=$sourceQuadrant, targetQuadrant=$targetQuadrant, insertIndex=$insertIndex',
);
final byId = {for (final todo in _todos) todo.id: todo};
final moving = byId[todoId];
print('DEBUG _reorderTodos: moving=$moving');
if (moving == null) {
print('DEBUG _reorderTodos: early return - moving is null');
return null;
}
final sourceList = _sortedQuadrantTodos(sourceQuadrant);
print('DEBUG _reorderTodos: sourceList.length=${sourceList.length}');
final targetList = sourceQuadrant == targetQuadrant
? sourceList
: _sortedQuadrantTodos(targetQuadrant);
final sourceIndex = sourceList.indexWhere((todo) => todo.id == todoId);
print('DEBUG _reorderTodos: sourceIndex=$sourceIndex');
if (sourceIndex == -1) {
print('DEBUG _reorderTodos: early return - sourceIndex is -1');
return null;
}
@@ -154,16 +173,33 @@ class _TodoQuadrantsScreenState extends State<TodoQuadrantsScreen> {
}
final moved = extracted.copyWith(priority: targetQuadrant);
print(
'DEBUG _reorderTodos: moved.priority=${moved.priority}, moved.order=${moved.order}',
);
mutableTarget.insert(targetIndex, moved);
print('DEBUG _reorderTodos: mutableTarget.length=${mutableTarget.length}');
for (var i = 0; i < mutableTarget.length; i++) {
print(
'DEBUG _reorderTodos: mutableTarget[$i] id=${mutableTarget[i].id}, priority=${mutableTarget[i].priority}, order=${mutableTarget[i].order}',
);
}
final updatedById = <String, TodoResponse>{};
void reindex(List<TodoResponse> list, int priority) {
print(
'DEBUG _reorderTodos: reindex called with priority=$priority, list.length=${list.length}',
);
for (var index = 0; index < list.length; index += 1) {
final current = list[index];
final updated = current.copyWith(priority: priority, order: index);
list[index] = updated;
print(
'DEBUG _reorderTodos: reindex item id=${current.id}, current.priority=${current.priority}, updated.priority=${updated.priority}, current.order=${current.order}, updated.order=${updated.order}',
);
if (current.priority != updated.priority ||
current.order != updated.order) {
print('DEBUG _reorderTodos: adding to updatedById id=${updated.id}');
updatedById[updated.id] = updated;
}
}
@@ -174,9 +210,12 @@ class _TodoQuadrantsScreenState extends State<TodoQuadrantsScreen> {
} else {
reindex(mutableSource, sourceQuadrant);
reindex(mutableTarget, targetQuadrant);
updatedById[moved.id] = moved;
}
print('DEBUG _reorderTodos: updatedById.length=${updatedById.length}');
if (updatedById.isEmpty) {
print('DEBUG _reorderTodos: returning null because updatedById is empty');
return null;
}
@@ -454,13 +493,19 @@ class _TodoQuadrantsScreenState extends State<TodoQuadrantsScreen> {
onWillAcceptWithDetails: (details) => true,
onAcceptWithDetails: (details) {
final info = details.data;
print(
'DEBUG: onAccept - sourceQuadrant=${info.sourceQuadrant}, targetQuadrant=$value, sourceIndex=${info.sourceIndex}, todoId=${info.todoId}',
);
if (info.sourceQuadrant != value) {
print('DEBUG: calling _onItemReorder');
_onItemReorder(
info.sourceIndex,
_listIndexByQuadrant(info.sourceQuadrant),
0,
_listIndexByQuadrant(value),
);
} else {
print('DEBUG: same quadrant, no reorder');
}
},
builder: (context, candidateData, rejectedData) {