# Twake Chat Client [![Contributors](https://img.shields.io/github/contributors/linagora/twake-on-matrix?label=Contributors)](https://github.com/linagora/twake-on-matrix/graphs/contributors) [![Issues](https://img.shields.io/github/issues/linagora/twake-on-matrix?label=Issues)](https://github.com/linagora/twake-on-matrix/issues) [![Documentation](https://img.shields.io/badge/Documentation-green.svg)](docs) [![Android application](https://img.shields.io/badge/App-Android-blue.svg)](https://play.google.com/store/apps/dev?id=8845244706987756601) [![Ios application](https://img.shields.io/badge/App-iOS-red.svg)](https://apps.apple.com/gr/developer/linagora/id1110867042)

Website • View Demo • Report Bug • Roadmap • Translate Twake

Twake Chat is an open source, decentralized chat app based on the Matrix protocol. It was developed by [Linagora](https://linagora.com). Twake Chat is a good option for individuals and organizations who are looking for a secure and decentralized chat app. It is also a good choice for developers who want to build their own Matrix-based chat apps. ## Features - Send all kinds of messages, images and files - Voice messages - Location sharing - Push notifications - Unlimited private and public group chats - Public channels with thousands of participants - Feature rich group moderation including all matrix features - Discover and join public groups - Dark mode - Custom themes - Hides complexity of Matrix IDs behind simple QR codes - Custom emotes and stickers - Spaces - Compatible with Element, Nheko, NeoChat and all other Matrix apps - End to end encryption - Emoji verification & cross signing - And much more... ## Development Please make sure to run the following command at first, to verify your code before each commit: ```bash bash scripts/config-pre-commit.sh ``` ### Requirements - [ ] Flutter 3.47.5 You can at any moment verify your flutter installation using: ```bash flutter doctor -v ``` #### Web For web development, install: - [Google Chrome](https://www.google.com/chrome/) - Rust using [rustup](https://rustup.rs/) - [yq](https://github.com/mikefarah/yq) The web target uses `flutter_vodozemac` for end-to-end encryption. Before running or building the application for the first time, generate the required web package: ```bash ./scripts/prepare-web.sh ``` Run this command again after updating the `flutter_vodozemac` dependency. #### Android - [ ] An implementation of JDK 17 _(tested with openjdk-17.0.13+11)_ - [ ] (Optional) Android Studio - [ ] An Android SDK with: - [ ] Android build tools: 34.0.0 - [ ] Android platform: 31, 32, 33, 34, 35 - [ ] CMake: 3.22.1 - [ ] Android NDK: 26.1.10909125 - [ ] Google APIs: enabled _Note: Gradle will try to install the JDK 8. If for any reasons the operation failed, try to install your own and use [this method](https://github.com/pm-McFly/twake-on-matrix/issues/1#issuecomment-2581428804) to tell Gradle where to find it._ #### Linux - [ ] Lib JsonCPP - [ ] Lib Secret - [ ] Lib RHash - [ ] Lib WebKit 2 GTK - [ ] Lib OLM _If needed, a complete list is available in the `flake.nix`._ On Ubuntu, the following command should install all the required elements: ```bash sudo apt install libjsoncpp1 libsecret-1-dev libsecret-1-0 librhash0 libwebkit2gtk-4.0-dev libolm3 ``` --- In addition, the Linux build requires Rust. For macOS or Linux, execute the following command in a terminal emulator: ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` For Windows, you can use the [Rust Installer](https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe). In case you have Rust already installed, make sure to update it to latest version: ```bash rustup update ``` #### [`devenv.nix`](devenv.nix) A `devenv.nix` is provided in order to ease the process of setting up your dev environment. Check out the install instructions: https://devenv.sh/getting-started/ Then you can use `devenv shell` to fire up your environment. _This can be automated thanks to: `[nix-direnv](https://github.com/nix-community/nix-direnv/)`_ Supported platforms: - [x] Linux x86_64 - [ ] MacOS aarch_64 - [ ] MacOS x86_64 - [ ] Windows WSL ### Configure the app In order to run the web target you must provide a default configuration file. This can be done by copying the `config.sample.json` to `config.json`. ```bash cp config.sample.json config.json ``` Here is an example working with `matrix.org`: ```json { "application_name": "Twake Chat", "application_welcome_message": "Welcome to Twake Chat!", "default_homeserver": "matrix.org", "privacy_url": "https://twake.app/en/privacy/", "render_html": true, "hide_unknown_events": true, "hide_redacted_events": false, "issue_id": "", "app_grid_dashboard_available": false, "homeserver": "https://matrix.org/", "platform": "localDebug", "default_max_upload_avatar_size_in_bytes": 1000000, "dev_mode": true, "qr_code_download_url": "https://sign-up.twake.app/download/chat", "enable_logs": true, "vapid_public_key": "", "web_push_enabled": false, "support_url": "https://twake.app/support", "cozy_external_bridge_version": "0.16.1" } ``` ### Running the code Before running the app, please update the dependencies: ```bash flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs ``` Now you can run the project: ```bash flutter devices # To list available run targets ``` ```bash # flutter run -d , e.g: flutter run -d chrome ``` ### Assets Asset references are generated by [`flutter_gen`](https://pub.dev/packages/flutter_gen) to provide type-safe accessors. The generated file is `lib/generated/assets.gen.dart` and must **never be edited by hand**. #### Adding a new asset 1. Put the file in the matching folder: - `assets/images/` — images and SVGs - `assets/icons/` — launcher icons - `assets/sounds/` — sounds - `assets/` — root-level assets (logos, Lottie files, etc.) - `configurations/icons/` — app grid configuration icons 2. If you created a new folder, declare it under `flutter: assets:` in `pubspec.yaml`. 3. Regenerate the accessors: ```bash flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs ``` #### Using assets Prefer the generated `Assets` accessors over hardcoded paths: ```dart import 'package:twake_chat/generated/assets.gen.dart'; // SVG SvgPicture.asset(Assets.images.icShieldLockFill.path); // Raster image Image.asset(Assets.images.chatBackground.path); // AssetImage (e.g. QR code decoration) AssetImage(Assets.logoPng.path); // Lottie animation LottieBuilder.asset(Assets.twakeLoading.path); ``` File names are converted to camelCase, e.g. `ic_shield_lock_fill.svg` → `Assets.images.icShieldLockFill` and `app_store.svg` → `Assets.images.appStore`. Folders become nested getters (`assets/images/` → `Assets.images`). ## Localization (Weblate) Translations are managed on [Weblate (Linagora / twake-matrix)](https://hosted.weblate.org/projects/linagora/twake-matrix/). - Translators: use the Weblate UI directly. - Source ARB files: `assets/l10n/` (template: `intl_en.arb`). - Sync branch: [`l10n`](https://github.com/linagora/twake-on-matrix/tree/l10n). Maintainers: the full sync process (rebase `l10n` on `main`, trigger the Weblate update/pull, open a PR from `l10n` into `main`) is documented in [docs/l10n_weblate_workflow.md](docs/l10n_weblate_workflow.md). ## Build Please use the helper script corresponding to your target in order to build: ### Web ```bash ./scripts/prepare-web.sh ./scripts/build-web.sh ``` ### Linux ```bash # ./scripts/build-linux.sh ## For release purposes ./scripts/build-linux-debug.sh ``` ### Android ```bash # ./scripts/build-android-apk.sh ## For release purposes ./scripts/build-android-debug.sh ``` ### Performance Profiling #### Why Chrome DevTools instead of Flutter DevTools? Flutter DevTools is designed for native (iOS/Android/Desktop) profiling and provides frame-level insights via the Dart VM. On **Flutter Web** however, the Dart code is compiled to JavaScript and runs inside a browser engine. Flutter DevTools cannot profile the JavaScript execution, browser rendering pipeline, or web worker scheduling. **Chrome DevTools Performance panel** is the right tool for Flutter Web because it captures the actual browser behavior: main thread long tasks, animation frame durations, garbage collection pauses, network timing, and GPU compositing — which is where the real bottlenecks are on web. #### The problem with manual analysis A Chrome DevTools performance trace recorded over a typical user session (navigating conversations, scrolling, viewing members) produces a **JSON file exceeding 350,000 lines**. The flame chart is virtually unreadable by eye for identifying patterns across hundreds of animation frames and long tasks. #### Automated profiling with Chrome DevTools MCP We use the [Chrome DevTools MCP](https://github.com/ChromeDevTools/chrome-devtools-mcp/?tab=readme-ov-file) server connected to an AI coding assistant (OpenCode + Claude Code) to **automate the entire profiling workflow**: 1. **Install the MCP server** — add to your OpenCode MCP configuration (~/.config/opencode/opencode.json): ```json { "$schema": "https://opencode.ai/config.json", "mcp": { "chrome-devtools": { "type": "local", "command": ["npx", "-y", "chrome-devtools-mcp@latest"] } } } ``` 2. **Switch to the original branch you want to compare with your changes** 3. **Ask Claude Opus 4.6 to perform the profiling** — example prompt: > Run the app on Chrome, in profile mode, connect via the Chrome DevTools MCP, set CPU throttling to 4x (recommended threshold to simulate a low-end device), start a performance trace, navigate through the app (open DM conversations, group rooms, scroll through messages, view member lists), stop the trace, and analyze the results. Compare before/after if applicable (Sync XHR (main thread), Animation frame avg, Jank, Long tasks, JS Heap). Every now and then, manually scroll through the app using your mouse to make sure that the programmatic scrolling isn't skewing the data. 4. **Switch to the branch where your changes are and ask again the AI to run the app and compare with the first run** 5. **What the AI does automatically**: - Connects to the running Chrome instance via the DevTools Protocol - Sets CPU 4x throttling to simulate a low-end device - Starts a performance trace recording - Navigates the app by dispatching pointer/wheel events on the Flutter canvas - Stops the trace and saves the raw JSON (typically 20+ MB compressed) - Parses the trace programmatically to extract: long tasks (>50ms), animation frame durations (avg, P95, P99, jank %), GC pauses, XHR/sync timing, JS heap size - Produces a comparison table if a baseline trace exists #### Key metrics to watch | Metric | Target | Description | | ---------------------- | -------- | ------------------------------------------------------------- | | Sync XHR (main thread) | < 50ms | Time spent parsing `/sync` responses on the main thread | | Animation frame avg | < 16.7ms | Average frame duration (60fps = 16.7ms budget) | | Jank (frames > 16.7ms) | < 20% | Percentage of frames that miss the 60fps deadline | | Long tasks (> 50ms) | Minimize | Tasks that block the main thread and cause visible stuttering | | JS Heap | Monitor | Memory pressure indicator — high values increase GC frequency | ## Deployment ### Web version using Docker #### Build web Docker image The image is built without SSH. The `web-builder` stage is pinned to `$BUILDPLATFORM`: it runs once, natively on the build host, and the final nginx stage carries platform-neutral web assets. CI builds and pushes `linux/amd64` and `linux/arm64` variants (see [`.github/workflows/image.yaml`](.github/workflows/image.yaml)). Build requirements (all Sentry values are injected from build args — nothing is hardcoded in the image): | Argument / secret | Required | Default | |--------------------------|----------|---------| | `--build-arg SENTRY_PROJECT` | yes | — | | `--build-arg SENTRY_ORG` | yes | — | | `--build-arg SENTRY_RELEASE` | no | version from `pubspec.yaml` | | `--build-arg SENTRY_DIST` | no | build number from `pubspec.yaml` | | `--build-arg SENTRY_DSN` | no | empty | | `--build-arg SENTRY_ENVIRONMENT` | no | empty | | `--secret id=sentry_auth_token,src=` | no | source maps not uploaded | Example local build: ```bash docker build \ --secret id=sentry_auth_token,src= \ --build-arg SENTRY_PROJECT=twake-chat \ --build-arg SENTRY_ORG=datcorp \ --build-arg SENTRY_ENVIRONMENT=prod \ -t linagora/twake-web: . ``` #### Run the web image - Create a config file `config.json` in the root of the project with the following [docs](https://github.com/linagora/twake-on-matrix/blob/main/docs/configurations/config_web_app_for_public_platform.md) - Run the image using the following command: ``` docker run -d -p : -e TWAKECHAT_LISTEN_PORT= --name -v :/usr/share/nginx/html/web/config.json linagora/twake-web: ``` - Open the browser and go to `http://localhost:` ### Sample to run Twake Chat web client with `matrix.org` - Create a config file `config.json` with `matrix.org` ```json { "app_grid_dashboard_available": true, "application_name": "Twake Chat", "application_welcome_message": "Welcome to Twake Chat!", "default_homeserver": "matrix.org", "hide_unknown_events": false, "homeserver": "https://matrix.org/", "issue_id": "", "privacy_url": "https://twake.app/en/privacy/", "render_html": true } ``` - Run the image using the following command with my port is `6868`: ``` docker run -d -p 6868:6868 -e TWAKECHAT_LISTEN_PORT=6868 --name twake-web -v /path/to/config.json:/usr/share/nginx/html/web/config.json linagora/twake-web:v2.19.7 ``` - Open the browser and go to `http://localhost:6868` # Special thanks - FluffyChat is the original repository of this project. A huge thanks to the upstream repository for their vital contributions, not only for this project but also for [Matrix SDK in Dart](https://github.com/famedly/matrix-dart-sdk) - Fabiyamada is a graphics designer from Brasil and has made the fluffychat logo and the banner. Big thanks for her great designs. - Advocatux has made the Spanish translation with great love and care. He always stands by my side and supports my work with great commitment. - Thanks to MTRNord and Sorunome for developing. - Also thanks to all translators and testers! With your help, fluffychat is now available in more than 12 languages. - Noto Emoji Font for the awesome emojis. - WoodenBeaver sound theme for the notification sound. - The Matrix Foundation for making and maintaining the [emoji translations](https://github.com/matrix-org/matrix-doc/blob/main/data-definitions/sas-emoji.json) used for emoji verification, licensed Apache 2.0