Skip to content

New chat UI#207

Merged
nfebe merged 6 commits into
devfrom
new-chat-ui
Jun 29, 2026
Merged

New chat UI#207
nfebe merged 6 commits into
devfrom
new-chat-ui

Conversation

@austin047

Copy link
Copy Markdown
Collaborator

Description

  • Redesign AI chat with typed blocks, attachments & actions

  • Added Blocks for rendering AI content from the server.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

- Add LocaleInterceptor that attaches the active Accept-Language header to outgoing requests
- Wire the interceptor into the Dio client in http_module
… and actions.

- New chat UI: launch landing (greeting, stats, continue/new), full-width assistant responses, chat history, and background polling for in-flight turns
- Typed agent blocks (markdown, table, kpi, chart, comparison, list, callout, timeline, progress, question, quick_actions, import_review, canvas) parsed in a sealed model, with a legacy SmartQL fallback
- Proposed actions: confirm, edit, or dismiss via a sealed, typed ActionField form (currency, wallet, party, enum, number, datetime, categories)
- Attachments: file picking with square image and document preview tiles, upload with deferred-turn release, inline retry, and file-too-large handling
- Add AI use cases (confirm action, reject action, upload files) with matching repository and datasource methods
- Add a file-too-large failure and surface it through the error handlers
- Localize the AI chat strings across all six languages
- Supporting updates: import document scan and file picker, AI chat navigation entry
- Add bloc lint and Patrol e2e testing plans
- Add sample AI query examples
@sourceant

sourceant Bot commented Jun 29, 2026

Copy link
Copy Markdown

Code Review Summary

This PR implements a significant upgrade to the AI chat experience. It adds support for multi-modal interactions (files), rich data visualization (charts, tables, KPIs), and interactive 'Proposed Actions' which allow the AI to draft transactions for user confirmation.

🚀 Key Improvements

  • Introduction of a structured block system for AI responses in lib/data/datasources/ai/dto/chat_blocks_dto.dart.
  • Enhanced AiChatCubit with polling and backoff strategies for asynchronous AI processing.
  • New Landing UI with data-driven insights and 'spotlight' tickers.
  • Support for attaching and re-compressing images before upload to the AI service.

💡 Minor Suggestions

  • Use the path package for filename manipulation.
  • Move widget-level timers into the Cubit.
  • Consider a more robust number formatting utility for financial data.

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review complete. See the overview comment for a summary.

void initState() {
super.initState();
_status = ImportSessionStatus.parse(widget.block.status);
if (widget.block.importSessionId != null && _status.isInFlight) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Polling logic is implemented directly within the Widget's initState. This makes the logic difficult to test and susceptible to memory leaks if not handled perfectly. This logic belongs in the AiChatCubit or a specialized Bloc to maintain a clean separation between UI and business logic.

Suggested change
if (widget.block.importSessionId != null && _status.isInFlight) {
// Logic should be handled in Cubit via a trigger
// context.read<AiChatCubit>().monitorImport(id);

String _fileName(File f) {
final last =
f.uri.pathSegments.isNotEmpty ? f.uri.pathSegments.last : 'file';
return last.replaceFirst(RegExp(r'^\d+_'), '');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex used to clean filenames from temporary paths assumes a specific prefix pattern that might change across OS versions or different image picker implementations. It's safer to use path.basename from the path package.

Suggested change
return last.replaceFirst(RegExp(r'^\d+_'), '');
import 'package:path/path.dart' as p;
return p.basename(f.path);

Comment on lines +50 to +51
if (v == null) return '-';
if (v is num) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fmtNum helper uses simple equality for round number detection. This can fail with precision issues common in floating point math. Consider using a threshold or num.toInt() check more defensively.

Suggested change
if (v == null) return '-';
if (v is num) {
if (v is num) {
return v % 1 == 0 ? v.toInt().toString() : v.toStringAsFixed(2);
}

@austin047 austin047 requested a review from nfebe June 29, 2026 16:58
@nfebe nfebe merged commit 9d4ba76 into dev Jun 29, 2026
3 checks passed
@nfebe nfebe deleted the new-chat-ui branch June 29, 2026 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants