**Major Features Added:** - **Inline Reply System**: Replace compose screen with inline reply boxes - **Thread Navigation**: Parent/child navigation with jump functionality - **Chain Flow UI**: Reply counts, expand/collapse animations, visual hierarchy - **Enhanced Animations**: Smooth transitions, hover effects, micro-interactions **Frontend Changes:** - **ThreadedCommentWidget**: Complete rewrite with animations and navigation - **ThreadNode Model**: Added parent references and descendant counting - **ThreadedConversationScreen**: Integrated navigation handlers - **PostDetailScreen**: Replaced with threaded conversation view - **ComposeScreen**: Added reply indicators and context - **PostActions**: Fixed visibility checks for chain buttons **Backend Changes:** - **API Route**: Added /posts/:id/thread endpoint - **Post Repository**: Include allow_chain and visibility fields in feed - **Thread Handler**: Support for fetching post chains **UI/UX Improvements:** - **Reply Context**: Clear indication when replying to specific posts - **Character Counting**: 500 character limit with live counter - **Visual Hierarchy**: Depth-based indentation and styling - **Smooth Animations**: SizeTransition, FadeTransition, hover states - **Chain Navigation**: Parent/child buttons with visual feedback **Technical Enhancements:** - **Animation Controllers**: Proper lifecycle management - **State Management**: Clean separation of concerns - **Navigation Callbacks**: Reusable navigation system - **Error Handling**: Graceful fallbacks and user feedback This creates a Reddit-style threaded conversation experience with smooth animations, inline replies, and intuitive navigation between posts in a chain.
359 lines
9.2 KiB
Markdown
359 lines
9.2 KiB
Markdown
# Android FCM Notifications - Troubleshooting Guide
|
|
|
|
## Issue: Chat notifications work on Web but not Android
|
|
|
|
### Current Status
|
|
- ✅ Web notifications working
|
|
- ✅ Android has `google-services.json` configured
|
|
- ✅ Android has FCM plugin in `build.gradle.kts`
|
|
- ✅ Android has notification permissions in `AndroidManifest.xml`
|
|
- ❓ Android FCM token registration status unknown
|
|
|
|
---
|
|
|
|
## Diagnostic Steps
|
|
|
|
### Step 1: Check Android Logs for FCM Token
|
|
|
|
Run the Android app with logging:
|
|
```bash
|
|
cd c:\Webs\Sojorn
|
|
.\run_dev.ps1
|
|
```
|
|
|
|
**In Android Studio or terminal, check logcat:**
|
|
```bash
|
|
adb logcat | findstr "FCM"
|
|
```
|
|
|
|
**Look for these log messages:**
|
|
```
|
|
[FCM] Initializing for platform: android
|
|
[FCM] Permission status: AuthorizationStatus.authorized
|
|
[FCM] Requesting token...
|
|
[FCM] Token registered (android): eXaMpLe...
|
|
[FCM] Syncing token with backend...
|
|
[FCM] Token synced with Go Backend successfully
|
|
[FCM] Initialization complete
|
|
```
|
|
|
|
### Step 2: Check for Common Errors
|
|
|
|
#### Error: "Token is null after getToken()"
|
|
**Cause:** Firebase not properly initialized or `google-services.json` mismatch
|
|
|
|
**Fix:**
|
|
1. Verify `google-services.json` package name matches:
|
|
```json
|
|
"package_name": "com.gosojorn.app"
|
|
```
|
|
2. Check `build.gradle.kts` has:
|
|
```kotlin
|
|
applicationId = "com.gosojorn.app"
|
|
```
|
|
3. Rebuild: `flutter clean && flutter pub get && flutter run`
|
|
|
|
#### Error: "Permission denied"
|
|
**Cause:** User denied notification permission or Android 13+ permission not requested
|
|
|
|
**Fix:**
|
|
1. Check `AndroidManifest.xml` has:
|
|
```xml
|
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
```
|
|
2. On Android 13+, permission must be requested at runtime
|
|
3. Uninstall and reinstall app to re-trigger permission prompt
|
|
|
|
#### Error: "Failed to initialize notifications"
|
|
**Cause:** Firebase plugin not properly initialized
|
|
|
|
**Fix:**
|
|
1. Check `android/build.gradle` (project level) has:
|
|
```gradle
|
|
dependencies {
|
|
classpath 'com.google.gms:google-services:4.4.0'
|
|
}
|
|
```
|
|
2. Check `android/app/build.gradle.kts` has:
|
|
```kotlin
|
|
plugins {
|
|
id("com.google.gms.google-services")
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Step 3: Verify Backend Receives Token
|
|
|
|
### Check Database for Android Tokens
|
|
|
|
SSH to server:
|
|
```bash
|
|
ssh -i "C:\Users\Patrick\.ssh\mpls.pem" patrick@194.238.28.122
|
|
```
|
|
|
|
Query database:
|
|
```bash
|
|
sudo -u postgres psql sojorn
|
|
```
|
|
|
|
```sql
|
|
-- Check for Android tokens
|
|
SELECT
|
|
user_id,
|
|
platform,
|
|
LEFT(fcm_token, 30) as token_preview,
|
|
created_at
|
|
FROM public.fcm_tokens
|
|
WHERE platform = 'android'
|
|
ORDER BY created_at DESC
|
|
LIMIT 5;
|
|
```
|
|
|
|
**Expected output:**
|
|
```
|
|
user_id | platform | token_preview | created_at
|
|
-------------------------------------+----------+--------------------------------+-------------------
|
|
5568b545-5215-4734-875f-84b3106cd170 | android | eXaMpLe_android_token_here... | 2026-01-29 06:00
|
|
```
|
|
|
|
**If no Android tokens:**
|
|
- Token registration failed
|
|
- Token sync to backend failed
|
|
- Check Android logs for errors
|
|
|
|
---
|
|
|
|
## Step 4: Test Push Notification Manually
|
|
|
|
### Send Test Notification from Server
|
|
|
|
```bash
|
|
# Get an Android FCM token from database
|
|
sudo -u postgres psql sojorn -c "SELECT fcm_token FROM public.fcm_tokens WHERE platform = 'android' LIMIT 1;"
|
|
```
|
|
|
|
The Go backend automatically sends notifications when:
|
|
- Someone sends you a chat message
|
|
- Someone follows you
|
|
- Someone accepts your follow request
|
|
|
|
**Test by sending a chat message:**
|
|
1. Open app on Android device
|
|
2. Have another user (or web browser) send you a message
|
|
3. Check Android logs for: `[FCM] Foreground message received`
|
|
|
|
---
|
|
|
|
## Step 5: Check Notification Channel (Android 8+)
|
|
|
|
Android 8+ requires notification channels. Check `strings.xml`:
|
|
|
|
**File:** `android/app/src/main/res/values/strings.xml`
|
|
```xml
|
|
<resources>
|
|
<string name="default_notification_channel_id">chat_messages</string>
|
|
<string name="default_notification_channel_name">Chat messages</string>
|
|
</resources>
|
|
```
|
|
|
|
**Referenced in AndroidManifest.xml:**
|
|
```xml
|
|
<meta-data
|
|
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
|
android:value="@string/default_notification_channel_id" />
|
|
```
|
|
|
|
---
|
|
|
|
## Common Issues & Solutions
|
|
|
|
### Issue 1: "google-services.json not found"
|
|
|
|
**Symptoms:**
|
|
- Build fails with "File google-services.json is missing"
|
|
- FCM token is null
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Verify file exists
|
|
ls sojorn_app/android/app/google-services.json
|
|
|
|
# If missing, download from Firebase Console:
|
|
# https://console.firebase.google.com/project/sojorn-a7a78/settings/general
|
|
# Click "Add app" > Android > Download google-services.json
|
|
```
|
|
|
|
### Issue 2: Package name mismatch
|
|
|
|
**Symptoms:**
|
|
- FCM token is null
|
|
- No errors in logs
|
|
|
|
**Solution:**
|
|
Verify all package names match:
|
|
1. `google-services.json`: `"package_name": "com.gosojorn.app"`
|
|
2. `build.gradle.kts`: `applicationId = "com.gosojorn.app"`
|
|
3. `AndroidManifest.xml`: `<manifest xmlns:android="...">` (no package attribute needed)
|
|
|
|
### Issue 3: Notification permission not granted
|
|
|
|
**Symptoms:**
|
|
- Log shows: `[FCM] Permission status: AuthorizationStatus.denied`
|
|
- No token generated
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Uninstall app
|
|
adb uninstall com.gosojorn.app
|
|
|
|
# Reinstall and allow notification permission when prompted
|
|
flutter run
|
|
```
|
|
|
|
### Issue 4: Token generated but not synced to backend
|
|
|
|
**Symptoms:**
|
|
- Log shows: `[FCM] Token registered (android): ...`
|
|
- Log shows: `[FCM] Sync failed: ...`
|
|
- No token in database
|
|
|
|
**Solution:**
|
|
Check API endpoint exists:
|
|
```bash
|
|
# On server
|
|
sudo journalctl -u sojorn-api -f | grep "notifications/device"
|
|
```
|
|
|
|
Verify Go backend has the endpoint:
|
|
```go
|
|
// Should be in cmd/api/main.go
|
|
authorized.POST("/notifications/device", settingsHandler.RegisterFCMToken)
|
|
```
|
|
|
|
---
|
|
|
|
## Comparison: Web vs Android
|
|
|
|
### Web (Working ✅)
|
|
- Uses VAPID key for authentication
|
|
- Service worker handles background messages
|
|
- Token format: `d2n2ELGKel7yzPL3wZLGSe:APA91b...`
|
|
|
|
### Android (Troubleshooting ❓)
|
|
- Uses `google-services.json` for authentication
|
|
- Native Android handles background messages
|
|
- Token format: Different from web, longer
|
|
- Requires runtime permission on Android 13+
|
|
|
|
---
|
|
|
|
## Debug Checklist
|
|
|
|
Run through this checklist:
|
|
|
|
- [ ] `google-services.json` exists in `android/app/`
|
|
- [ ] Package name matches in all files
|
|
- [ ] `build.gradle.kts` has `google-services` plugin
|
|
- [ ] `AndroidManifest.xml` has `POST_NOTIFICATIONS` permission
|
|
- [ ] App has notification permission granted
|
|
- [ ] Android logs show FCM initialization
|
|
- [ ] Android logs show token generated
|
|
- [ ] Token appears in database `fcm_tokens` table
|
|
- [ ] Backend logs show notification being sent
|
|
- [ ] Android logs show notification received
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. **Run the app with enhanced logging:**
|
|
```bash
|
|
cd c:\Webs\Sojorn
|
|
.\run_dev.ps1
|
|
```
|
|
|
|
2. **Monitor Android logs:**
|
|
```bash
|
|
adb logcat | findstr "FCM"
|
|
```
|
|
|
|
3. **Look for the specific log messages:**
|
|
- `[FCM] Initializing for platform: android`
|
|
- `[FCM] Token registered (android): ...`
|
|
- `[FCM] Token synced with Go Backend successfully`
|
|
|
|
4. **If token is null:**
|
|
- Check `google-services.json` is correct
|
|
- Verify package name matches
|
|
- Rebuild: `flutter clean && flutter pub get && flutter run`
|
|
|
|
5. **If token generated but notifications not received:**
|
|
- Check database has the token
|
|
- Send a test message
|
|
- Check backend logs for push notification being sent
|
|
- Verify Android device has internet connection
|
|
|
|
---
|
|
|
|
## Files to Check
|
|
|
|
### Android Configuration
|
|
- `sojorn_app/android/app/google-services.json` - Firebase config
|
|
- `sojorn_app/android/app/build.gradle.kts` - Build configuration
|
|
- `sojorn_app/android/app/src/main/AndroidManifest.xml` - Permissions
|
|
- `sojorn_app/android/app/src/main/res/values/strings.xml` - Notification channel
|
|
|
|
### Flutter Code
|
|
- `sojorn_app/lib/services/notification_service.dart` - FCM initialization (now with enhanced logging)
|
|
- `sojorn_app/lib/main.dart` - App initialization
|
|
|
|
### Backend
|
|
- `go-backend/internal/services/push_service.go` - Push notification sender
|
|
- `go-backend/internal/handlers/settings_handler.go` - FCM token registration endpoint
|
|
|
|
---
|
|
|
|
## Quick Commands
|
|
|
|
```bash
|
|
# Check Android logs
|
|
adb logcat | findstr "FCM"
|
|
|
|
# Check if app is installed
|
|
adb shell pm list packages | findstr gosojorn
|
|
|
|
# Uninstall app
|
|
adb uninstall com.gosojorn.app
|
|
|
|
# Check notification settings
|
|
adb shell dumpsys notification | findstr gosojorn
|
|
|
|
# Check database for tokens
|
|
ssh -i "C:\Users\Patrick\.ssh\mpls.pem" patrick@194.238.28.122
|
|
sudo -u postgres psql sojorn -c "SELECT platform, COUNT(*) FROM fcm_tokens GROUP BY platform;"
|
|
```
|
|
|
|
---
|
|
|
|
## Expected Behavior
|
|
|
|
**When working correctly:**
|
|
|
|
1. App starts → `[FCM] Initializing for platform: android`
|
|
2. Permission requested → User grants → `[FCM] Permission status: AuthorizationStatus.authorized`
|
|
3. Token generated → `[FCM] Token registered (android): eXaMpLe...`
|
|
4. Token synced → `[FCM] Token synced with Go Backend successfully`
|
|
5. Message sent → Backend sends push → `[FCM] Foreground message received`
|
|
6. Notification appears in Android notification tray
|
|
|
|
---
|
|
|
|
## Contact & Support
|
|
|
|
If issues persist after following this guide:
|
|
1. Share Android logcat output (filtered for FCM)
|
|
2. Share database query results for `fcm_tokens` table
|
|
3. Share backend logs when sending notification
|
|
4. Verify Firebase Console shows Android app is active
|