Repository files navigation # Hold2Send 🎙️
A private Android voice messaging app built with Flutter.
**Hold to Record. Release to Send. No text. No calls. Just your voice.**
---
## Features
| Feature | Details |
|---|---|
| 🔐 Auth | Google Sign-In via Firebase Authentication |
| 🆔 Custom UID | User picks a unique handle (e.g. `alice_voice`) |
| 👥 Friends | Add friends by their custom UID |
| 🎙️ Voice Messaging | Hold-to-record, release-to-send (`.m4a` format) |
| ☁️ Storage | Audio files stored in Appwrite Storage |
| 🔔 Notifications | Firebase Cloud Messaging push to receiver |
| 📥 Inbox | Play received voice messages in-app |
---
## Project Structure
```
lib/
├── main.dart # Entry point, Firebase init, routing
├── firebase_options.dart # ⚠️ Replace with generated file
│
├── models/
│ ├── app_user.dart # User data model
│ └── voice_message.dart # VoiceMessage data model
│
├── services/
│ ├── auth_service.dart # Firebase Auth + Google Sign-In
│ ├── firestore_service.dart # Firestore CRUD (users, friends, messages)
│ ├── appwrite_storage_service.dart # Appwrite file upload/delete/URL
│ └── messaging_service.dart # FCM token management + push dispatch
│
├── screens/
│ ├── splash_screen.dart # Loading screen during auth resolution
│ ├── auth/
│ │ └── login_screen.dart # Google Sign-In screen
│ ├── setup_uid_screen.dart # Custom UID picker (first launch only)
│ ├── home_screen.dart # Friends list + Inbox tabs
│ ├── friend_search_screen.dart # Search by custom UID & add friend
│ ├── voice_message_screen.dart # Hold-to-record screen
│ └── inbox_screen.dart # Received messages with playback
│
├── widgets/
│ └── friend_tile.dart # Reusable friend list tile
│
└── utils/
├── app_theme.dart # Dark theme & color palette
└── constants.dart # Appwrite config constants
```
---
## Setup Instructions
### 1. Prerequisites
- Flutter SDK ≥ 3.0.0
- Android Studio / VS Code
- Firebase project
- Appwrite project (cloud or self-hosted)
---
### 2. Firebase Setup
1. Go to [Firebase Console](https://console.firebase.google.com ) and create a new project.
2. **Enable Authentication:**
Authentication → Sign-in method → **Google** → Enable
3. **Enable Firestore:**
Firestore Database → Create database → Start in **production mode**
4. **Enable Cloud Messaging:**
Already enabled by default in Firebase projects.
5. **Add Android App:**
- Package name: `com.hold2send.hold2send`
- Download `google-services.json`
- Place it at: `android/app/google-services.json`
6. **Generate `firebase_options.dart`:**
```bash
dart pub global activate flutterfire_cli
flutterfire configure --project=
```
This replaces the placeholder `lib/firebase_options.dart`.
---
### 3. Firestore Security Rules
Go to **Firestore → Rules** and paste:
```js
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Users can read/write their own profile
match /users/{userId} {
allow read: if request.auth != null;
allow write: if request.auth.uid == userId;
// Friends sub-collection
match /friends/{friendId} {
allow read, write: if request.auth.uid == userId;
}
}
// Voice messages: sender can create, receiver can read/update (mark played)
match /voiceMessages/{messageId} {
allow create: if request.auth.uid == request.resource.data.senderId;
allow read: if request.auth.uid == resource.data.receiverId
|| request.auth.uid == resource.data.senderId;
allow update: if request.auth.uid == resource.data.receiverId;
}
}
}
```
---
### 4. Appwrite Setup
1. Go to your [Appwrite Console](https://cloud.appwrite.io ) (or self-hosted).
2. **Create a project** with ID: `hold2send`
*(Must match `AppwriteConfig.projectId` in `lib/utils/constants.dart`)*
3. **Create a Storage Bucket:**
- Bucket ID: `voice-messages`
- Permissions: `Any` can **create** (for authenticated users you can restrict by JWT)
- Allowed file extensions: `m4a`, `aac`
- Max file size: `25 MB` (recommended)
4. The endpoint is already configured:
`https://nyc.cloud.appwrite.io/v1`
---
### 5. Firebase Cloud Messaging (Push Notifications)
> **⚠️ Important:** FCM server keys must **never** be in your Flutter app.
> Set up a Cloud Function (or any backend) to proxy FCM calls.
**Option A — Firebase Cloud Functions (recommended):**
```javascript
// functions/index.js
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.sendNotification = functions.https.onRequest(async (req, res) => {
const { receiverToken, title, body } = req.body;
await admin.messaging().send({
token: receiverToken,
notification: { title, body },
});
res.json({ success: true });
});
```
Deploy and set the URL in `lib/screens/voice_message_screen.dart`:
```dart
const backendUrl = 'https://YOUR_REGION-YOUR_PROJECT.cloudfunctions.net/sendNotification ';
```
**Option B — Skip notifications for now:**
Remove the `sendVoiceMessageNotification` call. Messages still save and receivers see them in the Inbox on next open.
---
### 6. Install Dependencies
```bash
flutter pub get
```
---
### 7. Run the App
```bash
flutter run
```
For a release build:
```bash
flutter build apk --release
```
The APK will be at: `build/app/outputs/flutter-apk/app-release.apk`
---
## Firestore Data Model
### `users/{userId}`
```json
{
"userId": "firebase_uid",
"customUid": "alice_voice",
"displayName": "Alice",
"photoUrl": "https://...",
"fcmToken": "fcm_registration_token",
"createdAt": "Timestamp"
}
```
### `users/{userId}/friends/{friendUserId}`
```json
{
"addedAt": "Timestamp"
}
```
### `voiceMessages/{messageId}`
```json
{
"senderId": "firebase_uid",
"receiverId": "firebase_uid",
"appwriteFileId": "appwrite_file_id",
"appwriteBucketId": "voice-messages",
"audioUrl": "https://nyc.cloud.appwrite.io/v1/storage/ ...",
"duration": 12,
"createdAt": "Timestamp",
"isPlayed": false
}
```
---
## Tech Stack
| Layer | Technology |
|---|---|
| Framework | Flutter (Android) |
| Auth | Firebase Authentication (Google) |
| Database | Cloud Firestore |
| File Storage | Appwrite Storage |
| Push Notifications | Firebase Cloud Messaging |
| Audio Recording | `record` package |
| Audio Playback | `audioplayers` package |
---
## Important Notes
- ❌ No text chat
- ❌ No live calls
- ❌ No live audio streaming
- ✅ Voice messages only
- ✅ Android first (iOS can be added later)
---
## License
MIT
# Yapi
You can’t perform that action at this time.