* feat(mobile): lock chat input while bot is responding + 20s timeout
- Add _isWaitingForResponse flag to ChatProvider; set in _startPolling,
cleared in _stopPolling so it covers the full polling lifecycle not
just the initial HTTP POST
- Add _pollingStartTime + 20s timeout in _pollForUpdates; if the bot
never responds the flag resets, errorMessage is surfaced, and input
unlocks automatically
- Gate send button and keyboard shortcut on isSendingMessage ||
isWaitingForResponse so users cannot queue up multiple messages
while a response is in flight
(adding an interrupt like with other chat bots would require a larger rewrite of the backend structure)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(mobile): make polling timeout measure inactivity not total duration
Reset _pollingStartTime whenever assistant content grows so the 20s
timeout only fires if no new content has arrived in that window.
Prevents cutting off a slow-but-streaming response mid-generation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(mobile): lock input for full polling duration, not just until first chunk
- Add isPolling getter to ChatProvider (true while _pollingTimer is active)
- Gate send button and intent on isPolling in addition to isWaitingForResponse
so users cannot submit overlapping prompts while a response is still streaming
- Also auto-scroll while polling is active
* Fix chat polling timeout race and send re-entry guard
Polling timeout was evaluated before the network attempt, allowing it
to fire just as a response became ready. Timeout check now runs after
each poll attempt and only when no progress was made; network errors
fall through to the same check instead of silently swallowing the tick.
Added _isSendInFlight boolean to prevent rapid taps from re-entering
_sendMessage() during the async token fetch window before provider
flags are set. Guard is set synchronously at the top of the method and
cleared in a finally block.
* fix(mobile): prevent overlapping polls and empty-placeholder stop
Add _isPollingRequestInFlight guard so Timer.periodic ticks are
skipped if a getChat request is still in flight, preventing stale
results from resetting state out of order.
Fix empty assistant placeholder incorrectly triggering _stopPolling:
stable is only declared when a previously observed length exists and
hasn't grown. An initial empty message keeps polling until content
arrives or the timeout fires.
* fix(mobile): reset _lastAssistantContentLength in _stopPolling
Prevents stale content-length state from a prior polling session
bleeding into the next one.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(mobile): render assistant messages as markdown, keep user text plain
Add flutter_markdown dependency and conditionally render chat bubbles:
- User messages use plain Text to avoid formatting markdown characters
- Assistant messages use MarkdownBody with styled headings, bold, italic,
lists and code blocks matching the existing color scheme
- Bump Dart SDK constraint to >=3.3.0 to satisfy flutter_markdown 0.7.2
* fix(mobile): address markdown rendering review comments
- Extract MarkdownStyleSheet into _markdownStyle() helper to avoid
rebuilding TextStyles on every message render
- Replace deprecated imageBuilder with sizedImageBuilder; block http/https
image URIs to prevent unsolicited remote fetches from AI-generated content
- Commit updated pubspec.lock with flutter_markdown 0.7.2 resolved
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix tests
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
* feat(mobile): Add animated TypingIndicator widget for AI chat responses
Replaces the static CircularProgressIndicator + "AI is thinking..." text
with an animated TypingIndicator showing pulsing dots while the AI generates
a response. Respects the app color scheme so it works in light and dark themes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix: Normalize stagger progress to [0,1) in TypingIndicator to prevent negative opacity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(mobile): fix typing indicator visibility and run pub get
The typing indicator was only visible for the duration of the HTTP
POST (~instant) because it was tied to `isSendingMessage`. It now
tracks the full AI response lifecycle via a new `isWaitingForResponse`
state that stays true through polling until the response stabilises.
- Add `isWaitingForResponse` to ChatProvider; set on poll start,
clear on poll stop with notifyListeners so the UI reacts correctly
- Move TypingIndicator inside the ListView as an assistant bubble
so it scrolls naturally with the conversation
- Add provider listener that auto-scrolls on every update while
waiting for a response
- Redesign TypingIndicator: 3-dot sequential bounce animation
(classic chat style) replacing the simultaneous fade
* feat(mobile): overhaul new-chat flow and fix typing indicator bugs
chat is created lazily
on first send, eliminating all pre-conversation flashes and crashes
- Inject user message locally into _currentChat immediately on createChat
so it renders before the first poll completes
- Hide thinking indicator the moment the first assistant content arrives
(was waiting one extra 2s poll cycle before disappearing)
- Fix double-spinner on new chat: remove manual showDialog spinner and
use a local _isCreating flag on the FAB instead
* fix(mboile) : address PR review — widget lifecycle safety and new-chat regression
* Fic(mobile): Add mounted check in post-frame callback
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Chat improvements
* Delete/reset account via API for Flutter app
* Fix tests.
* Add "contact us" to settings
* Update mobile/lib/screens/chat_conversation_screen.dart
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Juan José Mata <jjmata@jjmata.com>
* Improve LLM special token detection
* Deactivated user shouldn't have API working
* Fix tests
* API-Key usage
* Flutter app launch failure on no network
* Handle deletion/reset delays
* Local cached data may become stale
* Use X-Api-Key correctly!
---------
Signed-off-by: Juan José Mata <jjmata@jjmata.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Backend fixes:
- Fix duplicate AssistantResponseJob triggering causing duplicate AI responses
- UserMessage model already handles job triggering via after_create_commit callback
- Remove redundant job enqueue in chats_controller and messages_controller
Mobile app features:
- Implement complete AI chat interface and conversation management
- Add Chat, Message, and ToolCall data models
- Add ChatProvider for state management with polling mechanism
- Add ChatService to handle all chat-related API requests
- Add chat list screen (ChatListScreen)
- Add conversation detail screen (ChatConversationScreen)
- Refactor navigation structure with bottom navigation bar (MainNavigationScreen)
- Add settings screen (SettingsScreen)
- Optimize TransactionsProvider to support account filtering
Technical details:
- Implement message polling mechanism for real-time AI responses
- Support chat creation, deletion, retry and other operations
- Integrate Material Design 3 design language
- Improve user experience and error handling
Co-authored-by: dwvwdv <dwvwdv@protonmail.com>