{"id":50514344,"url":"https://github.com/adiksuu/justtalk","last_synced_at":"2026-06-02T23:00:36.093Z","repository":{"id":362132077,"uuid":"1249229553","full_name":"Adiksuu/justtalk","owner":"Adiksuu","description":"JustTalk – A modern, real-time full-stack chat application with E2E encyption","archived":false,"fork":false,"pushed_at":"2026-06-02T19:59:33.000Z","size":6305,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-06-02T21:23:24.048Z","etag":null,"topics":["android","development","expo","messaging","mobile-app","react-native"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Adiksuu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-25T13:36:48.000Z","updated_at":"2026-06-02T20:14:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Adiksuu/justtalk","commit_stats":null,"previous_names":["adiksuu/justtalk"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/Adiksuu/justtalk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adiksuu%2Fjusttalk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adiksuu%2Fjusttalk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adiksuu%2Fjusttalk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adiksuu%2Fjusttalk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Adiksuu","download_url":"https://codeload.github.com/Adiksuu/justtalk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adiksuu%2Fjusttalk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33840214,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","development","expo","messaging","mobile-app","react-native"],"created_at":"2026-06-02T23:00:23.178Z","updated_at":"2026-06-02T23:00:36.085Z","avatar_url":"https://github.com/Adiksuu.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JustTalk\n\nA real-time mobile messaging application built with React Native and Expo, targeting Android and iOS (iOS maybe later :p). JustTalk provides end-to-end encrypted conversations, multi-provider authentication, media sharing via Cloudinary, and a suite of interactive chat features -- all backed by Firebase Realtime Database for low-latency data synchronization.\n\n**Current version:** 1.0.15 \n**Package identifier:** `pl.adiksuu.justtalk`  \n**License:** MIT\n\n\u003cimg src=\"./assets/images/banners/showcase.png\"\u003e\n\n---\n\n## Table of Contents\n\n1. [Overview](#overview)\n2. [Technology Stack](#technology-stack)\n3. [Architecture](#architecture)\n4. [Features](#features)\n5. [Project Structure](#project-structure)\n6. [Authentication](#authentication)\n7. [Real-Time Systems](#real-time-systems)\n8. [Encryption](#encryption)\n9. [Media Pipeline](#media-pipeline)\n10. [Notifications](#notifications)\n11. [User Interface](#user-interface)\n12. [Build and Deployment](#build-and-deployment)\n13. [Getting Started](#getting-started)\n14. [Scripts](#scripts)\n\n---\n\n## Overview\n\nJustTalk is a privacy-focused chat application designed for direct, one-to-one messaging. Every text message, image URL, and video URL stored in the database is encrypted with AES-256 using a per-conversation key derived from the chat identifier. The application leverages Firebase Realtime Database listeners to deliver messages, typing indicators, presence updates, and read receipts with minimal latency.\n\nThe project is structured as a single Expo Router application with file-based routing, TypeScript for static type safety, and a clean separation between business logic, UI components, and data interfaces.\n\n---\n\n## Technology Stack\n\n| Layer | Technology | Purpose |\n|---|---|---|\n| **Framework** | React Native 0.81.5, Expo SDK 54 | Cross-platform mobile runtime |\n| **Language** | TypeScript 5.9 (strict mode) | Static type checking across the codebase |\n| **Routing** | Expo Router 6 | File-based navigation with typed routes |\n| **Database** | Firebase Realtime Database | Persistent storage and real-time data sync |\n| **Authentication** | Firebase Auth | Multi-provider identity management |\n| **Media Storage** | Cloudinary | Image and video upload, transformation, and delivery |\n| **Encryption** | CryptoJS (AES) | Client-side message encryption and decryption |\n| **State** | React built-in (useState, useMemo, useRef) | Local component state management |\n| **Animations** | React Native Animated API, React Native Reanimated 4 | Transition and gesture-driven animations |\n| **Gestures** | React Native Gesture Handler 2.28 | Swipe-to-reply, double-tap reactions, long-press menus |\n| **List Rendering** | Shopify FlashList 2.0 | High-performance virtualized message lists |\n| **Keyboard** | React Native Keyboard Controller 1.18 | Keyboard-aware input positioning |\n| **Haptics** | Expo Haptics | Tactile feedback for interactions |\n| **Notifications** | Expo Notifications | Push notification delivery via Expo push service |\n| **Biometrics** | Expo Local Authentication | Fingerprint and face authentication |\n| **Image Viewing** | react-native-image-viewing | Full-screen image gallery |\n| **Video Playback** | expo-video 3.0 | In-chat and full-screen video playback |\n| **Screen Capture** | Expo Screen Capture | Screenshot detection and notification |\n| **Compilation** | React Compiler (experimental) | Automatic memoization at build time |\n\n---\n\n## Architecture\n\nThe application follows a feature-oriented architecture with clear boundaries between layers:\n\n```\nsrc/\n  app/          Screen-level components (Expo Router file-based routes)\n  components/   Reusable UI components, organized by domain\n  functions/    Business logic and Firebase operations (pure functions)\n  hooks/        Custom React hooks (theming, color scheme)\n  interfaces/   TypeScript type definitions\n  constants/    Static data (country codes)\n```\n\n**Data flow:** Screens subscribe to Firebase Realtime Database paths through listener functions defined in `src/functions/`. These listeners use `onValue` to push updates reactively into component state. Outgoing operations (sending messages, managing friends) are handled through imperative async functions in the same module.\n\n**Navigation model:** The app uses Expo Router's Stack navigator with three primary routes (`/`, `/login`, `/profile`) and two dynamic route groups (`/auth/*` for authentication flows, `/chat/[id]` for conversations). Auth state is observed at the root level and drives automatic redirection between authenticated and unauthenticated screens.\n\n---\n\n## Features\n\n### Messaging\n- Real-time message delivery using Firebase Realtime Database listeners\n- AES-256 encryption applied to all message text and media URLs before storage\n- Support for five message types: text, image, video, system, and typing indicator\n- Rich URL link previews with metadata extraction via `link-preview-js`\n- Message pagination with progressive loading (10 messages per batch)\n- Inverted FlashList rendering for chat-standard bottom-to-top message ordering\n- Message deletion (soft delete with `isRemoved` flag)\n- Swipe-to-reply with visual reply preview in the input bar\n- Message reply threading with inline preview in the conversation\n- Message projects stored in the device's memory\n- \u003cimg src=\"./assets/images/banners/message_showcase.png\" height=\"550\"\u003e\n\n### Reactions\n- Double-tap gesture to toggle a heart reaction\n- Long-press gesture to open a full reaction menu with five options\n- Per-user reaction tracking stored at the message level in Firebase\n- Reaction toggle behavior (re-selecting the same reaction removes it)\n\n### Presence and Activity\n- Online/offline presence tracking using Firebase `onDisconnect` handlers\n- Last-seen timestamps updated automatically on disconnect\n- Real-time typing indicators per conversation\n- Typing state automatically cleared on navigation away from a chat\n\n### Read Receipts\n- Read timestamps recorded per user per conversation\n- Real-time subscription to the friend's read timestamp\n- Messages visually marked as read when their timestamp precedes the friend's last-read time\n- Unread message count computed and displayed on the chat list\n\n### Friend Management\n- User search by display name with debounced query execution\n- Friend request lifecycle: send, cancel, accept, decline\n- Separate filtered views for Friends, Incoming requests, and Outgoing requests\n- Friend removal with optional biometric confirmation\n- Custom nickname assignment per friend, per conversation\n- Empty state handling when the friend list is empty\n- Change chat accent theme, per conversation\n\n### Media\n- Image and video selection from the device gallery via Expo Image Picker\n- Upload to Cloudinary with automatic resource type detection\n- Encrypted media URLs stored alongside messages\n- Shared media gallery in the chat info subscreen\n- Full-screen image viewer with swipe navigation\n- Full-screen video player with native playback controls\n- Cloudinary-based video thumbnail generation (`.mp4` to `.jpg` extension swap)\n\n### Profile\n- User profile display with avatar, name, email, phone number, and join date\n- Avatar upload via Cloudinary with real-time database update\n- Initials-based fallback avatar rendering\n- User ID copy-to-clipboard with animated toast confirmation\n- Application version display from Expo config\n- \u003cimg src=\"./assets/images/banners/profile_showcase.png\" height=\"550\"\u003e\n\n### Settings\n- Haptic feedback toggle (light and heavy impact styles)\n- Push notification permission toggle\n- Biometric authentication toggle\n- Preferences persisted locally via AsyncStorage\n\n### Security\n- Screenshot detection within active chat screens\n- Automated system message notifying the conversation when a screenshot is taken\n- Biometric authentication gate for sensitive actions (friend removal)\n- Client-side AES encryption for all stored message content\n\n### Connectivity\n- Network connectivity monitoring with periodic health checks\n- Dedicated offline state UI when the connection is lost\n\n---\n\n## Project Structure\n\n```\njusttalk/\n  app.json                  Expo application configuration\n  eas.json                  EAS Build profiles (development, preview, production)\n  package.json              Dependencies and scripts\n  tsconfig.json             TypeScript configuration with path aliases\n  google-services.json      Firebase Android configuration\n  assets/\n    images/                 App icons, splash screen, and static assets\n  src/\n    app/\n      _layout.tsx           Root layout (SafeAreaProvider, KeyboardProvider, StatusBar)\n      index.tsx             Home screen (chat list, filters, tab bar)\n      login.tsx             Login screen (phone and email entry points)\n      profile.tsx           Profile screen (user info, settings, logout)\n      auth/\n        email.tsx           Email sign-in and sign-up form\n        phone.tsx           Phone number verification with OTP input\n      chat/\n        [id].tsx            Chat conversation screen (messages, input, info subscreen)\n    components/\n      auth/\n        email/              Email authentication form components\n        phone/              Phone authentication form components\n      chat/\n        Avatar.tsx          Initials-based avatar with Firebase-backed image\n        ChatEmptyState.tsx  Empty conversation placeholder\n        ChatHeader.tsx      Chat screen header with back navigation and info trigger\n        ChatInfoSubscreen.tsx  Modal with friend profile, media gallery, and actions\n        InputBar.tsx        Message input with attachment, camera, and reply support\n        MessageBubble.tsx   Message renderer with gesture detection and decryption\n        MessagePreview.tsx  Inline reply preview\n        ReactionMenu.tsx    Long-press reaction picker with delete option\n        ReadReceipt.tsx     Read status indicator\n        RenderReactions.tsx Reaction badge renderer\n        ReplyBox.tsx        Reply context bar above the input\n        ScrollToBottom.tsx  Floating scroll-to-bottom button\n        details/\n          Header.tsx        Info subscreen header\n          Informations.tsx  Friend account details\n          Medias.tsx        Shared media grid\n          ProfileInfo.tsx   Friend avatar, name (editable), and status\n          RemoveFriendModal.tsx  Animated confirmation modal for friend removal\n          VideoPlayer.tsx   Full-screen video player modal\n          ChatThemes.tsx    Chat theme selector\n        messageTypes/\n          ImageMessage.tsx  Image message renderer with full-screen preview\n          LinkPreviewMessage.tsx  URL preview with metadata extraction\n          SystemMessage.tsx Centered system notification message\n          TextMessage.tsx   Standard text message bubble\n          TypingMessage.tsx Animated typing indicator\n          VideoMessage.tsx  Inline video player with playback controls\n      profile/\n        Avatar.tsx          Profile avatar with upload capability\n        BottomSheetModal.tsx Animated bottom sheet for logout confirmation\n        FloatingToast.tsx   Animated toast notification\n        Header.tsx          Profile screen header\n        cards/\n          card_1.tsx        Account information card\n          card_2.tsx        Preferences card (haptics, notifications, biometrics)\n          Logout.tsx        Logout action card\n      ui/\n        ChatList.tsx        Friends list with real-time chat state listeners\n        Filters.tsx         Filter chips (Friends, Incoming, Outgoing)\n        Header.tsx          Home screen header with animated search\n        NoConnection.tsx    Offline state display\n        friends/\n          NoFriends.tsx     Empty friends list state\n          ResultsDropdownList.tsx  Search results dropdown\n          SearchFriend.tsx  Animated search input\n          SearchResult.tsx  Individual search result with add/cancel actions\n      utils/\n        ChatItem.tsx        Chat list item row\n        ImagePreview.tsx    Full-screen image viewer wrapper\n        TabBar.tsx          Bottom navigation with capsule, classic, and floating styles\n    functions/\n      activity.ts          Presence, typing status, and read receipt operations\n      auth.ts              Authentication flows (phone, email, Google, Facebook, biometric)\n      crypto.ts            AES encryption and decryption functions\n      friends.ts           Friend request lifecycle and user search\n      media.ts             Image/video picking, Cloudinary upload, and media gallery\n      messages.ts          Message CRUD, real-time subscriptions, and reactions\n      notifications.ts     Push notification registration and delivery\n      preferences.ts       Local preference management with haptic feedback\n      profile.ts           User profile fetching and formatting\n      utility.ts           Shared utility functions\n    hooks/\n      use-color-scheme.ts  Platform-specific color scheme detection\n      use-theme.ts         Theme hook\n    interfaces/\n      Message.ts           Message and MessageType type definitions\n      SharedMediaItem.ts   Shared media item type definition\n      UserProfileData.ts   User profile type definition\n    constants/\n      COUNTRIES.ts         Country code data for phone authentication\n      THEMES.ts            Chat themes data (accent colors)\n    global.css             CSS custom properties for web typography\n```\n\n---\n\n## Authentication\n\nJustTalk supports four authentication providers, all managed through Firebase Auth:\n\n| Provider | Flow |\n|---|---|\n| **Email/Password** | Standard sign-up with email verification, sign-in with error handling |\n| **Phone Number** | SMS-based OTP verification with 6-digit code input and 60-second cooldown |\n| **Google** | OAuth via `@react-native-google-signin/google-signin` with offline access |\n| **Facebook** | OAuth via `react-native-fbsdk-next` with public_profile and email permissions |\n\nAfter successful authentication, the user's profile data (UID, display name, email, phone number, creation timestamp) is written to the Firebase Realtime Database under `users/{uid}`. The root layout observes `onAuthStateChanged` and redirects to the login screen when no authenticated session exists.\n- \u003cimg src=\"./assets/images/banners/auth_showcase.png\" height=\"550\"\u003e\n\n\n---\n\n## Real-Time Systems\n\nThe application maintains several concurrent real-time subscriptions through Firebase Realtime Database `onValue` listeners:\n\n| System | Database Path | Purpose |\n|---|---|---|\n| **Messages** | `chats/{chatId}/messages/` | Real-time message delivery with pagination |\n| **Typing** | `typing/{chatId}/{uid}` | Per-user typing indicator with `onDisconnect` cleanup |\n| **Presence** | `presence/{uid}` | Online/offline state with automatic disconnect handling |\n| **Read Receipts** | `chats/{chatId}/read/{uid}` | Per-user last-read timestamp |\n| **Friend Requests** | `friends_requests/{uid}/incoming/` and `outgoing/` | Request state changes |\n| **Friends List** | `friends/{uid}/` | Friend additions and removals |\n| **Custom Usernames** | `chats/{chatId}/usernames/{uid}/chatUsername` | Per-friend nickname changes |\n| **Chat Themes** | `chats/{chatId}/theme` | Per-chat accent theme changes |\n\nAll listeners are properly cleaned up in `useEffect` return functions to prevent memory leaks.\n\n---\n\n## Encryption\n\nAll message content is encrypted client-side before being written to Firebase:\n\n- **Algorithm:** AES-256 via CryptoJS\n- **Key derivation:** The chat ID (`{uid1}_{uid2}`, lexicographically ordered) serves as the symmetric key\n- **Scope:** Both message text and media URLs are encrypted independently\n- **Decryption:** Performed at render time within the `MessageBubble` component using `useMemo` for performance\n\nThe encryption covers all message types including text, image URLs, video URLs, and reply references. System messages (screenshot notifications) are also encrypted.\n\n---\n\n## Media Pipeline\n\n```\nUser selects media (Expo Image Picker)\n    |\n    v\nResource type detected (image/video)\n    |\n    v\nUploaded to Cloudinary via multipart form POST\n    |\n    v\nSecure URL returned\n    |\n    v\nURL encrypted with AES (chat ID as key)\n    |\n    v\nStored in Firebase Realtime Database as message\n    |\n    v\nDecrypted at render time for display\n```\n\n- **Image quality:** 0.8 compression\n- **Video quality:** UIImagePickerControllerQualityType.Medium\n- **Upload preset:** `justtalk_app` (unsigned, Cloudinary-managed)\n- **Thumbnails:** Video thumbnails generated by replacing the file extension with `.jpg` in the Cloudinary URL\n\n---\n\n## Notifications\n\nPush notifications are delivered through the Expo push notification service:\n\n1. On app launch, the device's Expo push token is registered and stored in Firebase under `users/{uid}/pushToken`\n2. When a message is sent, the sender fetches the recipient's push token from the database\n3. A POST request is made to `https://exp.host/--/api/v2/push/send` with the message content\n4. Notifications display the sender's name as the title and the message text as the body\n\n---\n\n## User Interface\n\nThe interface uses a dark color scheme (`#0B0C0E` background) with an indigo accent (`#6366F1`) and follows these design principles:\n\n- **Navigation:** Floating capsule-style bottom tab bar with animated active state\n- **Chat list:** Friends sorted by most recent message, with unread count badges and last message previews\n- **Conversations:** Inverted list with bottom-to-top rendering, keyboard-aware input bar, and swipe gestures\n- **Animations:** Animated transitions on the login screen (pulsing brand text), profile screen (fade-in with slide), search bar (expand/collapse), toast notifications, and bottom sheet modals\n- **Safe areas:** Consistent safe area handling across all screens using `react-native-safe-area-context`\n- **Haptic feedback:** Configurable tactile feedback on message send, reactions, and preference changes\n\n---\n\n## Build and Deployment\n\nThe project uses Expo Application Services (EAS) for builds:\n\n| Profile | Distribution | Format | Purpose |\n|---|---|---|---|\n| **development** | Internal | Development client | Local development with hot reload |\n| **preview** | Internal | APK | Internal testing and distribution |\n| **production** | Default | AAB | Store submission |\n\nThe React Compiler experimental flag is enabled in `app.json` for automatic component memoization.\n\n---\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js (LTS)\n- Expo CLI\n- Android Studio or a physical Android device\n- Firebase project with Realtime Database and Authentication enabled\n- Cloudinary account with an unsigned upload preset\n\n### Installation\n\n```bash\ngit clone https://github.com/Adiksuu/justtalk.git\ncd justtalk\nnpm install\n```\n\n### Development\n\n```bash\nnpx expo start\n```\n\nFor Android native builds:\n\n```bash\nnpx expo run:android\n```\n\n---\n\n## Scripts\n\n| Script | Command | Description |\n|---|---|---|\n| `start` | `expo start` | Start the Expo development server |\n| `android` | `expo run:android` | Build and run on Android |\n| `ios` | `expo run:ios` | Build and run on iOS |\n| `web` | `expo start --web` | Start the web development server |\n| `lint` | `expo lint` | Run the linter |\n| `reset-project` | `node ./scripts/reset-project.js` | Reset the project to a clean state |\n\n---\n\nBuilt by [Adiksuu](https://github.com/Adiksuu)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadiksuu%2Fjusttalk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadiksuu%2Fjusttalk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadiksuu%2Fjusttalk/lists"}