"A pocket-sized friend who actually listens. Powered by AI, fueled by good vibes." β¨
You know that friend who always knows what to say when you're having a rough day? Emo is that friend β except it runs on your phone, never sleeps, never judges you, and is powered by Google's Gemini AI instead of 10 years of therapy.
Emo is a cross-platform Flutter app that gives you a safe space to type out how you're feeling, and replies with genuinely warm, empathetic, emoji-peppered responses. Think of it as a diary that talks back β in the most supportive way possible.
It maintains conversational context (so it remembers what you just said), saves the bot's best responses locally for you to revisit, and runs on literally every platform Flutter supports. It's dark-themed, snappy, and built with love (and http.post).
Place a demo GIF here once you've recorded one:
assets/demo.gif
What the GIF should show:
- Typing a message into the chat input ("I'm having a stressful day")
- The loading spinner while Gemini thinks
- The empathetic reply appearing as a message bubble
- Opening the drawer to see saved messages
- Deleting a saved message with the trash icon
Keep it around 5β10 seconds, looping. Nobody wants to download a 50MB GIF.
Emo is a single-screen Flutter app with three main logical layers:
| Layer | What it does |
|---|---|
| UI Layer | Chat bubbles, text input, send button, drawer panel |
| Logic Layer | _sendMessage() builds the prompt, calls Gemini, updates state |
| Storage Layer | shared_preferences persists bot responses between sessions |
The app is intentionally kept simple β one file, one screen, zero over-engineering. It's a reminder that not every project needs a BLoC + repository pattern + dependency injection to be genuinely useful.
| Feature | Description |
|---|---|
| π¬ Contextual Chat | Remembers your last message and the bot's last response to maintain natural conversation flow |
| π€ Emotional Support AI | Prompt-engineered to give brief, caring, emoji-friendly replies β not generic chatbot fluff |
| π AMOLED Dark UI | Pure #121212 background β your battery and your eyes will thank you |
| πΎ Saved Messages | Bot responses you love get persisted locally via shared_preferences |
| ποΈ Delete Saved Messages | Swipe open the drawer, tap the trash icon β message gone, no drama |
| π Truly Cross-Platform | Android, iOS, Web, Linux, macOS, Windows β one codebase, all the places |
| β‘ Gemini 1.5 Flash | Fast, intelligent responses via Google's generative AI β not some janky rule-based bot |
| π Auto-scroll | Chat auto-scrolls to the latest message because manually scrolling is so 2010 |
AI Empathy Quality Response Speed Platform Coverage Local Persistence Context Awareness UI Responsiveness
90% 85% 100% 80% 75% 95%
State management: Plain StatefulWidget + setState β no BLoC, no Riverpod, no Redux. This is a conscious choice. The app is single-screen. Don't over-engineer it.
Persistence: shared_preferences stores bot responses as a string list. Lightweight, zero-config, perfect for this use case.
Networking: http package makes a POST to the Gemini REST endpoint. No fancy GraphQL, no gRPC. Just good ol' HTTP.
Typography: google_fonts loads Playfair Display for the app title. Because serif fonts in a dark AMOLED theme hit different.
- Flutter SDK β₯ 3.0.0 (check with
flutter --version) - A Google Gemini API key β free tier available at Google AI Studio
- Dart SDK β₯ 3.0.0 (comes with Flutter, relax)
- A device or emulator to run it on (or just use
flutter run -d chrome)
# 1. Clone the repo (you know the drill)
git clone https://github.com/Kaelith69/Emo.git
cd Emo
# 2. Get dependencies
flutter pub get
# 3. Open lib/main.dart and swap in your API key
# (line ~18, look for _kApiKey)
# 4. Run it
flutter run
# Or target a specific platform:
flutter run -d android
flutter run -d ios
flutter run -d chrome
flutter run -d windows
flutter run -d linux
flutter run -d macosOpen lib/main.dart and replace the placeholder:
// lib/main.dart β line ~18
const String _kApiKey = 'YOUR_GEMINI_API_KEY';
β οΈ Seriously though: Do not commit a real API key. Use environment variables,--dart-define, or a secrets manager for production builds. Future self will thank you.# One approach with --dart-define at build time: flutter run --dart-define=GEMINI_KEY=your_actual_key_here
- Launch the app β you'll see the
Emotitle and a chat input at the bottom - Type how you're feeling β be honest, it won't judge you
- Hit Send (or press Enter) β the spinner appears while Gemini processes
- Read the reply β warm, empathetic, emoji-packed goodness
- Open the drawer (menu icon, top-left) to see all saved bot responses
- Delete saved messages you no longer need with the ποΈ icon
- Keep chatting β context from your last exchange is included automatically
| Property | Value |
|---|---|
| Provider | Google Generative AI |
| Model | gemini-1.5-flash |
| Endpoint | POST /v1beta/models/gemini-1.5-flash:generateContent |
| Temperature | 0.9 (creative, warm, not robotic) |
| Candidate count | 1 |
Request body shape:
{
"contents": [{ "parts": [{ "text": "<crafted prompt with context>" }] }],
"generationConfig": { "temperature": 0.9, "candidateCount": 1 }
}Response extraction:
candidates[0]['content']['parts'][0]['text']Emo/
βββ lib/
β βββ main.dart β The whole app. Yep, one file.
β βββ MyApp β MaterialApp root, dark theme config
β βββ MyHomePage β Stateful chat screen
β β βββ _sendMessage() β Builds prompt, calls Gemini, updates UI
β β βββ _addMessage() β Appends to message list + auto-scrolls
β β βββ _saveMessage() β Persists bot reply to SharedPreferences
β βββ Message β Immutable data model (text + isUser flag)
β βββ MessageBubble β Stateless chat bubble (user: purple, bot: dark)
β βββ MyDrawer β Stateful saved-messages side panel
βββ test/
β βββ widget_test.dart β Widget tests (render, send, drawer, empty input)
βββ android/ β Android-specific config
βββ ios/ β iOS-specific config
βββ web/ β Web build files
βββ linux/ β Linux desktop
βββ macos/ β macOS desktop
βββ windows/ β Windows desktop
βββ pubspec.yaml β Dependencies & metadata
βββ analysis_options.yaml β Dart linter config
βββ assets/
βββ demo.gif β (Add your demo GIF here)
| Package | Version | Purpose |
|---|---|---|
flutter |
SDK | UI framework |
google_fonts |
^6.0.0 | Playfair Display for the app title |
http |
^1.1.0 | HTTP client for Gemini API calls |
shared_preferences |
^2.2.1 | Local persistence of bot responses |
cupertino_icons |
^1.0.2 | iOS-style icons |
- No data leaves your device except the text you explicitly type and send
- API calls go directly to Google's Generative AI API β only your message + conversation context is transmitted
- No analytics, no tracking, no telemetry β none of that nonsense is in this codebase
- Local storage uses
shared_preferencesβ stored on-device only, never synced to a server - API key is stored in the source code (placeholder by default) β you are responsible for securing it in production
See SECURITY.md for vulnerability reporting.
- Secure API key loading via
--dart-defineor environment variable - Message search within saved messages
- Light mode / system theme support
- Multi-turn structured conversation history (not just last-message context)
- Export chat history to a text or JSON file
- Daily affirmation push notifications
- Haptic feedback on send
- Accessibility improvements (screen reader support)
flutter testThe test suite covers:
- β App renders title and chat input
- β Send button is enabled initially, disabled during loading
- β Empty input does not trigger a send (no phantom blank messages)
- β Drawer opens and shows the "Saved Messages" header
Pull requests are welcome β check out CONTRIBUTING.md for the full rundown.
Short version: fork β branch β commit β PR. Be kind, write tests, don't commit API keys.
Distributed under the MIT License. See LICENSE for details.
Β© 2025 Sayanth T M
π Report a bug Β· π€ Contribute Β· π Wiki
