Skip to content

Conversation

@Muneerali199
Copy link

@Muneerali199 Muneerali199 commented Jan 25, 2026

Description

This PR updates all project dependencies to their latest stable versions to address security vulnerabilities, ensure compatibility with the latest Flutter/Dart SDKs, and improve overall stability.

Key Updates

  • flutter_secure_storage: ^9.2.4^10.0.0 (Major security update)
  • app_links: ^6.4.1^7.0.0 (Major update for deep linking)
  • google_fonts: ^6.3.2^8.0.0 (Major UI stability update)
  • firebase_core/messaging/analytics: Updated to latest compatible minor versions.
  • Updated 69+ transitive dependencies to resolve flutter pub outdated warnings.

Type of Change

  • 🔧 Chore (updates to build process or auxiliary tools and libraries)

Checklist

  • My code follows the style guidelines of this project.
  • I have performed a self-review of my own code.
  • I have verified that the app builds without dependency errors.

Summary by CodeRabbit

  • Chores

    • Updated dependencies and raised Android min SDK to 23
  • New Features

    • Audio output selector and device switching in call/room screens
    • Added Bengali, Punjabi, and Tamil localizations
  • Improvements

    • Safer storage reads/writes with fallback defaults on errors
    • Message deletion UX (delete flow and deleted-message visuals)
    • Empty-state screens for friends/friend-requests
  • Documentation

    • Added detailed CHANGELOG and release/issue templates

✏️ Tip: You can customize this high-level summary in your review settings.

@Muneerali199 Muneerali199 requested a review from M4dhav as a code owner January 25, 2026 14:05
@github-actions
Copy link
Contributor

🎉 Welcome @Muneerali199!
Thank you for your pull request! Our team will review it soon. 🔍

  • Please ensure your PR follows the contribution guidelines. ✅
  • All automated tests should pass before merging. 🔄
  • If this PR fixes an issue, link it in the description. 🔗

We appreciate your contribution! 🚀

@coderabbitai
Copy link

coderabbitai bot commented Jan 25, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Migrates Appwrite document APIs to TablesDB/row APIs, adds audio output selection (model, controller, UI, tests), expands localization (bn/pa/ta + keys), introduces message deletion, secures FlutterSecureStorage usage with androidOptions, updates Android minSdk, CI/workflows, CODEOWNERS, dependabot, and many tests/docs.

Changes

Cohort / File(s) Summary
Appwrite migration (TablesDB)
lib/controllers/*, lib/services/appwrite_service.dart, lib/services/*, lib/views/widgets/*, test/controllers/*
Replaced Databases/Document APIs with TablesDB/Row APIs across controllers, services, widgets and tests: listDocumentslistRows, getDocumentgetRow, createDocumentcreateRow, updateDocumentupdateRow, deleteDocumentdeleteRow; renamed collection/document identifiers to table/row IDs; updated mocks and tests.
Audio device feature
lib/controllers/audio_device_controller.dart, lib/models/audio_device.dart, lib/utils/enums/audio_device_enum.dart, lib/views/widgets/audio_selector_dialog.dart, test/controllers/audio_device_controller_test.dart
New AudioDevice model + AudioDeviceController, audio device enum, UI selector bottom sheet, controller tests, and wiring into call/room/live screens to select audio output.
Message deletion
lib/models/message.dart, lib/controllers/room_chat_controller.dart, lib/views/screens/room_chat_screen.dart
Added Message.isDeleted field, propagation to toJson/fromJson/copyWith; RoomChatController updated to support delete flow; chat UI shows deleted state and exposes delete action with confirmation.
Secure storage & startup
lib/utils/constants.dart, lib/main.dart, lib/views/screens/app_preferences_screen.dart, lib/services/room_service.dart
Added androidOptions for FlutterSecureStorage, replaced direct storage calls with guarded FlutterSecureStorage(aOptions: androidOptions) usage and try/catch fallbacks for reads/writes in startup, preferences, and room flows.
Localization expansion
lib/l10n/*, lib/l10n/app_localizations.dart, ios/Runner/Info.plist, l10n.yaml
Added Bengali/Punjabi/Tamil localizations and many new keys across locales; updated AppLocalizations to support new locales and strings; updated Info.plist/locales and l10n.yaml.
UI additions / empty states
lib/views/screens/friends_empty_screen.dart, lib/views/screens/friends_screen.dart, lib/views/screens/friend_requests_screen.dart
New FriendsEmptyState widget and empty-state handling for friends/requests; minor UI adjustments in multiple screens (audio settings FAB, leave button styling).
Tests & mocks
test/controllers/*, test/controllers/* .mocks.dart
Extensive test updates to reflect TablesDB/Row API: regenerated mocks, updated test data shapes (Row/RowList), and added audio device controller tests.
Dependency & Android change
pubspec.yaml, android/app/build.gradle.kts
Bumped app_links, flutter_secure_storage, google_fonts; set Android minSdk to literal 23.
CI / repo tooling
.github/*, CHANGELOG.md, COPYRIGHT.md, README.md, ONBOARDING.md
Added CODEOWNERS, Dependabot config, multiple ISSUE_TEMPLATEs, updated PR template, large workflow changes to build_and_deploy (cleanup, artifact path, changelog parsing), added CHANGELOG/COPYRIGHT and doc edits.
Miscellaneous theme/enum/model updates
lib/themes/theme.dart, lib/models/*, lib/utils/enums/*
Added ColorScheme tokens, new enums/models, small EOF/format fixes, and other minor refactors.

Sequence Diagram(s)

sequenceDiagram
  participant App as App (main)
  participant Storage as FlutterSecureStorage
  participant Logger as Logger

  App->>Storage: initialize with AndroidOptions (try)
  alt storage responds
    Storage-->>App: return languageLocale, whisperModel
    App->>App: map savedModel -> WhisperModel (orElse default)
    App->>Logger: (optional) info
    App->>App: runApp()
  else storage error
    Storage--x App: throw/return error
    App->>Logger: log error
    App->>App: use defaults (language="en", WhisperModel.base)
    App->>App: runApp()
  end
Loading
sequenceDiagram
  participant UI as User UI
  participant Dialog as Audio Selector Dialog
  participant Controller as AudioDeviceController
  participant Media as WebRTC/mediaDevices

  UI->>Dialog: open selector
  Dialog->>Controller: instantiate / refreshDevices()
  Controller->>Media: navigator.mediaDevices.enumerateDevices()
  Media-->>Controller: list of MediaDeviceInfo
  Controller-->>Dialog: emit audio output devices
  UI->>Dialog: tap device
  Dialog->>Controller: selectAudioOutput(device)
  Controller->>Media: setSinkId / select output (if supported)
  Controller-->>UI: selectedAudioOutput update
  UI->>Dialog: done -> close
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • M4dhav

Poem

🐇 I hopped through lines of code, small and bright,
Tables and rows took flight in the night.
Speakers chosen, messages hushed with care,
Secure little vaults now guard what’s there.
A rabbit applauds—soft thumps, one, two, three—hooray! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title claims to update 'all dependencies to latest versions' but the changes show selective updates (three direct dependencies in pubspec.yaml) and Android SDK configuration changes, not a comprehensive dependency update across all areas. Revise the title to be more specific about the primary change: consider 'chore: migrate flutter_secure_storage to v10 and update dependencies' or focus on the security/migration aspects that are actually implemented.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@pubspec.yaml`:
- Line 51: Upgrade actions for flutter_secure_storage v10: ensure your Android
minSdkVersion >= 23 (update android/app/build.gradle if needed), then locate
where FlutterSecureStorage is instantiated (instances used to store
createdRoomAdminToken, createdRoomLivekitUrl, languageLocale, whisperModel) and
add explicit AndroidOptions to control migration/reset behavior (set
migrateOnAlgorithmChange and resetOnError explicitly instead of relying on
defaults) and handle potential decryption failures by catching errors and
providing a fallback/migration path; finally, run end-to-end tests for
login/token persistence on both fresh installs and upgraded devices to verify no
data loss.

flutter_onboarding_slider: ^1.0.11
flutter_otp_text_field: ^1.5.1+1
flutter_secure_storage: ^9.2.4
flutter_secure_storage: ^10.0.0
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

flutter_secure_storage 10.0.0 pub.dev version status stable beta 2025

💡 Result:

flutter_secure_storage 10.0.0 is a stable (non‑prerelease) release on pub.dev—it appears under “Stable versions” (min Dart SDK 3.3) and was published in late 2025 (shown as “~45 days ago” as of Jan 2026). [1]

There are also 10.0.0 beta prereleases (e.g., 10.0.0-beta.1 … beta.5) listed separately under “Prerelease versions”; the changelog documents the 10.0.0-beta.* series as the prerelease track used during 2025. [1], [2]


🏁 Script executed:

#!/bin/bash
# Check flutter_secure_storage usage patterns in codebase

echo "=== Checking current secure storage usage ==="
rg -n 'FlutterSecureStorage|AndroidOptions|IOSOptions' --type dart -A 3 2>/dev/null || echo "No matches found"

echo ""
echo "=== Checking for encryptedSharedPreferences configuration ==="
rg -n 'encryptedSharedPreferences' --type dart 2>/dev/null || echo "No encryptedSharedPreferences found"

echo ""
echo "=== Checking current pubspec.yaml for flutter_secure_storage ==="
grep -n 'flutter_secure_storage' pubspec.yaml 2>/dev/null || echo "Not found in pubspec.yaml"

echo ""
echo "=== Checking Android minSdkVersion ==="
find . -name 'build.gradle' -type f 2>/dev/null | head -5 | xargs grep -n 'minSdk' 2>/dev/null || echo "No explicit minSdk found"

echo ""
echo "=== Checking Android configuration in pubspec/gradle ==="
if [ -f "android/app/build.gradle" ]; then
  head -50 android/app/build.gradle | grep -E 'minSdk|compileSdk|targetSdk'
else
  echo "android/app/build.gradle not found"
fi

Repository: AOSSIE-Org/Resonate

Length of output: 2873


🌐 Web query:

flutter_secure_storage 10.0.0 stable breaking changes migration issues 2025

💡 Result:

Key flutter_secure_storage 10.0.0 (stable) breaking changes / migration pain points (notably across 2025 as v10 moved from betas to stable):

  • Android implementation rewrite (Jetpack Security deprecated): v10 replaces the old Jetpack Security–based approach with custom ciphers, updates defaults to RSA-OAEP (SHA-256) for key wrapping and AES-GCM for storage, and adds migration tooling. This can surface “data disappeared / can’t decrypt” reports if migration/reset behaviors trigger. [1][2]
  • encryptedSharedPreferences effectively on the way out: AndroidOptions().encryptedSharedPreferences is now deprecated. Migration is generally automatic because migrateOnAlgorithmChange defaults to true; if you were relying on the old behavior, you may need to explicitly manage encryptedSharedPreferences + migrateOnAlgorithmChange combinations during rollout. [1]
  • resetOnError now defaults to true on Android (previously you may have relied on it being off). This can look like “storage got wiped” after unrecoverable keystore/cipher errors unless you explicitly set resetOnError: false (with the tradeoff that failures may persist). [1]
  • Minimum Android SDK raised to 23 and Java 17 is required for the Android side. Apps supporting Android < 6.0 can’t stay on v10. [1]
  • iOS/macOS changes: iOS+macOS are unified under flutter_secure_storage_darwin, and minimum iOS is raised (9 → 12). [1]
  • Web breaking-ish changes: web support was modernized for WASM, removed older js usage in favor of interop, and added “secure context” checks (HTTPS/localhost). This also helps resolve some 2025-era dependency conflicts people hit on v9.x web transitive deps (e.g., js constraint conflicts). [1][3]
  • Toolchain constraints: v10 requires at least Dart 3.3 / Flutter 3.19 (introduced during the v10 betas and applies to v10). [1]
  • Timeline note: 10.0.0 stable landed ~late 2025 (pub.dev shows “uploaded 45 days ago” relative to now). [4]

Practical migration checklist (most common blockers)

  1. Ensure your app meets min SDK / toolchain: Android minSdk 23, Java 17, Flutter/Dart constraints. [1]
  2. If upgrading from v9.x on Android, explicitly decide:
    • keep default auto-migration (migrateOnAlgorithmChange: true), or
    • temporarily control behavior (especially if you previously forced/avoided encryptedSharedPreferences). [1]
  3. Review whether resetOnError: true could be masking an underlying keystore/device-security issue by wiping values. [1]
  4. If you had web dependency pinning issues on v9.x, re-run resolution after moving to v10 (web deps changed significantly). [1][3]

Sources: pub.dev v10 changelog [1], GitHub repo notes [2], 2025 dependency-conflict issue [3], pub.dev versions page [4].


🏁 Script executed:

#!/bin/bash
# Try alternative methods to find Android configuration
echo "=== Checking for Android gradle files ==="
find . -path "*/android/*.gradle" -type f 2>/dev/null

echo ""
echo "=== Checking android directory structure ==="
if [ -d "android" ]; then
  find android -name "*.gradle" -o -name "build.gradle.kts" 2>/dev/null | head -10
else
  echo "No android directory found"
fi

echo ""
echo "=== Checking for gradle.properties ==="
find . -name "gradle.properties" 2>/dev/null

echo ""
echo "=== Checking pubspec.yaml for flutter_secure_storage details ==="
grep -A 5 -B 5 'flutter_secure_storage' pubspec.yaml

Repository: AOSSIE-Org/Resonate

Length of output: 653


🏁 Script executed:

#!/bin/bash
# Check Android minSdk configuration
echo "=== android/app/build.gradle.kts ==="
cat android/app/build.gradle.kts 2>/dev/null | grep -E 'minSdk|compileSdk|targetSdk' || echo "Not found or different format"

echo ""
echo "=== android/build.gradle.kts ==="
cat android/build.gradle.kts 2>/dev/null | head -30

echo ""
echo "=== android/gradle.properties ==="
cat android/gradle.properties 2>/dev/null || echo "Not found"

echo ""
echo "=== Check for any Dart/Flutter version constraints ==="
grep -E 'sdk:|flutter:' pubspec.yaml | head -5

Repository: AOSSIE-Org/Resonate

Length of output: 1152


flutter_secure_storage 10.0.0 has breaking changes — verify data migration and test auth flows before release.

Version 10.0.0 is a stable release (not beta), but includes significant breaking changes from v9.x:

  • Android minSdk raised to 23 (from 19). If your app's minSdkVersion is below 23, upgrade required.
  • encryptedSharedPreferences is deprecated. Auto-migration is enabled by default (migrateOnAlgorithmChange: true), but if you previously relied on disabling encryption, verify the migration path explicitly.
  • Storage cipher changed: Jetpack Crypto replaced with custom ciphers (RSA-OAEP + AES-GCM); migration can surface decryption failures.
  • resetOnError now defaults to true on Android. Unrecoverable keystore errors will auto-wipe stored values—verify this doesn't mask underlying device issues for your use case.

Critical for this codebase: Auth tokens (createdRoomAdminToken, createdRoomLivekitUrl) and configuration values (languageLocale, whisperModel) are stored via FlutterSecureStorage. Test login flows and token persistence thoroughly on both new installs and upgraded existing data before production release.

Recommendation: If staying on v10.0.0, add explicit AndroidOptions configuration to control migration behavior, or test the defaults rigorously to ensure no data loss during the upgrade.

🤖 Prompt for AI Agents
In `@pubspec.yaml` at line 51, Upgrade actions for flutter_secure_storage v10:
ensure your Android minSdkVersion >= 23 (update android/app/build.gradle if
needed), then locate where FlutterSecureStorage is instantiated (instances used
to store createdRoomAdminToken, createdRoomLivekitUrl, languageLocale,
whisperModel) and add explicit AndroidOptions to control migration/reset
behavior (set migrateOnAlgorithmChange and resetOnError explicitly instead of
relying on defaults) and handle potential decryption failures by catching errors
and providing a fallback/migration path; finally, run end-to-end tests for
login/token persistence on both fresh installs and upgraded devices to verify no
data loss.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@android/app/build.gradle.kts`:
- Line 40: The build currently sets minSdk = 23 which is required by
flutter_secure_storage v10 and drops Android API 21–22 support; update project
release materials and stakeholder notifications to reflect this breaking change,
add an inline comment next to the minSdk declaration referencing
"flutter_secure_storage v10 required" for future maintainers, and ensure Play
Console/Release Notes and any marketing or internal onboarding docs explicitly
state Android 6.0+ (API 23) is now the minimum supported device level.

In `@lib/services/room_service.dart`:
- Around line 194-204: The Appwrite participant cleanup must only run after a
successful LiveKit deletion: in the function using FlutterSecureStorage
(storage) read the "createdRoomAdminToken" into livekitToken and if livekitToken
== null return early (do not proceed), then call await
apiService.deleteRoom(roomId, livekitToken) and if that call throws let the
exception bubble (or rethrow) instead of catching and continuing; only after
deleteRoom completes successfully continue with Appwrite participant/document
deletion logic so Appwrite cleanup is skipped whenever the LiveKit deletion is
skipped or fails.
- Around line 179-189: The current deletion block silently ignores a missing
token and swallows exceptions; update the logic around FlutterSecureStorage /
storage.read("createdRoomAdminToken") and
apiService.deleteLiveChapterRoom(roomId, livekitToken) to surface failures to
the UI: if livekitToken is null call Get.snackbar(...) with a clear message that
LiveKit token is missing and deletion cannot proceed, and inside the catch call
Get.snackbar(...) including the caught error (e.toString()) so the user sees the
failure; do not just print the error—log it and surface it via Get.snackbar and
optionally rethrow or return a failure result so callers can react.

In `@lib/utils/constants.dart`:
- Around line 5-13: The AndroidOptions constant androidOptions currently sets
resetOnError: true which will wipe flutter_secure_storage on unrecoverable
crypto/KeyStore errors; change this to resetOnError: false and add explicit
migration/error handling where secure storage is read (or, alternatively, if you
intentionally accept data loss, add a clear comment next to the
AndroidOptions/androidOptions declaration documenting why wiping is acceptable
and the expected failure/recovery policy). Update references to
AndroidOptions/androidOptions usage sites to handle and surface migration/crypto
errors so the app can fallback or prompt re-authentication instead of silently
losing data.
🧹 Nitpick comments (3)
lib/views/screens/app_preferences_screen.dart (2)

141-147: Don’t silently ignore preference save failures.

If the write fails, the UI still reflects the new language but it won’t persist. Consider logging and/or user feedback so failures are detectable.

Minimal feedback/logging
-                } catch (e) {
-                  // log error
-                }
+                } catch (e) {
+                  Get.snackbar("Error", "Failed to save language preference");
+                }

213-222: Centralize secure-storage writes to avoid drift.

This block mirrors the language preference write. A small helper (e.g., _savePreference(String key, String value)) keeps error handling consistent and reduces duplication across settings.

lib/services/room_service.dart (1)

111-120: Extract a helper for storing room credentials.

The same storage-write block appears in createLiveChapterRoom. A shared helper improves consistency (and makes it easier to add retries/telemetry later).

Comment on lines +179 to +188
try {
const storage = FlutterSecureStorage(aOptions: androidOptions);

// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
await apiService.deleteLiveChapterRoom(roomId, livekitToken!);
// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
if (livekitToken != null) {
await apiService.deleteLiveChapterRoom(roomId, livekitToken);
}
} catch (e) {
print("Error deleting live chapter room: $e");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if file exists and read the relevant section
fd "room_service.dart" --type f

Repository: AOSSIE-Org/Resonate

Length of output: 93


🏁 Script executed:

# Read the file to see lines around 179-189 with context
wc -l lib/services/room_service.dart

Repository: AOSSIE-Org/Resonate

Length of output: 97


🏁 Script executed:

# Read the relevant section with context
sed -n '170,200p' lib/services/room_service.dart | cat -n

Repository: AOSSIE-Org/Resonate

Length of output: 1453


🏁 Script executed:

# Search for callers of deleteLiveChapterRoom
rg "deleteLiveChapterRoom" -B 2 -A 2 --type dart

Repository: AOSSIE-Org/Resonate

Length of output: 2090


🏁 Script executed:

# Find and read context around the call in live_chapter_controller.dart
rg "deleteLiveChapterRoom" -B 10 -A 5 lib/controllers/live_chapter_controller.dart

Repository: AOSSIE-Org/Resonate

Length of output: 656


🏁 Script executed:

# Search for Get.snackbar usage in codebase
rg "Get\.snackbar" --type dart | head -20

Repository: AOSSIE-Org/Resonate

Length of output: 501


🏁 Script executed:

# Read more of room_service.dart to understand error handling patterns
sed -n '1,100p' lib/services/room_service.dart | cat -n

Repository: AOSSIE-Org/Resonate

Length of output: 3945


🏁 Script executed:

# Read more sections to see error handling patterns
sed -n '100,160p' lib/services/room_service.dart | cat -n

Repository: AOSSIE-Org/Resonate

Length of output: 2509


🏁 Script executed:

# Check the deleteRoom method to see if it has similar issue
sed -n '192,220p' lib/services/room_service.dart | cat -n

Repository: AOSSIE-Org/Resonate

Length of output: 1327


Add error handling and user feedback when token is missing or deletion fails.

The method silently skips deletion if the token is null and silently suppresses any exceptions, leaving the room orphaned on LiveKit with no feedback to the user. Surface errors using Get.snackbar() (already used in this file) so the UI can notify users when critical operations fail.

Example handling
   static Future deleteLiveChapterRoom({required roomId}) async {
     try {
       const storage = FlutterSecureStorage(aOptions: androidOptions);
-      // Delete room on livekit and roomdoc on appwrite
       String? livekitToken = await storage.read(key: "createdRoomAdminToken");
-      if (livekitToken != null) {
-        await apiService.deleteLiveChapterRoom(roomId, livekitToken);
-      }
+      if (livekitToken == null) {
+        Get.snackbar("Error", "Missing admin token. Room not deleted.");
+        return;
+      }
+      await apiService.deleteLiveChapterRoom(roomId, livekitToken);
     } catch (e) {
-      print("Error deleting live chapter room: $e");
+      Get.snackbar("Error", "Failed to delete live chapter room: $e");
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
const storage = FlutterSecureStorage(aOptions: androidOptions);
// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
await apiService.deleteLiveChapterRoom(roomId, livekitToken!);
// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
if (livekitToken != null) {
await apiService.deleteLiveChapterRoom(roomId, livekitToken);
}
} catch (e) {
print("Error deleting live chapter room: $e");
}
try {
const storage = FlutterSecureStorage(aOptions: androidOptions);
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
if (livekitToken == null) {
Get.snackbar("Error", "Missing admin token. Room not deleted.");
return;
}
await apiService.deleteLiveChapterRoom(roomId, livekitToken);
} catch (e) {
Get.snackbar("Error", "Failed to delete live chapter room: $e");
}
🤖 Prompt for AI Agents
In `@lib/services/room_service.dart` around lines 179 - 189, The current deletion
block silently ignores a missing token and swallows exceptions; update the logic
around FlutterSecureStorage / storage.read("createdRoomAdminToken") and
apiService.deleteLiveChapterRoom(roomId, livekitToken) to surface failures to
the UI: if livekitToken is null call Get.snackbar(...) with a clear message that
LiveKit token is missing and deletion cannot proceed, and inside the catch call
Get.snackbar(...) including the caught error (e.toString()) so the user sees the
failure; do not just print the error—log it and surface it via Get.snackbar and
optionally rethrow or return a failure result so callers can react.

Comment on lines +194 to +203
try {
const storage = FlutterSecureStorage(aOptions: androidOptions);

// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
await apiService.deleteRoom(roomId, livekitToken!);
// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
if (livekitToken != null) {
await apiService.deleteRoom(roomId, livekitToken);
}
} catch (e) {
print("Error deleting room: $e");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the deleteRoom function in room_service.dart to see the complete implementation
fd -t f "room_service.dart" --exec head -c 50000 {} \;

Repository: AOSSIE-Org/Resonate

Length of output: 10249


Prevent Appwrite cleanup when LiveKit deletion fails.

The function deletes Appwrite participant documents unconditionally, even if the LiveKit deletion is skipped (missing token) or fails with an exception. This causes data desync—LiveKit rooms persist while Appwrite records are deleted.

Add early returns to ensure Appwrite cleanup only happens after successful LiveKit deletion:

  • Return early if livekitToken == null
  • Return early if apiService.deleteRoom() throws an exception (don't silently catch and continue)
Example early-return to maintain consistency
static Future deleteRoom({required roomId}) async {
  RoomsController roomsController = Get.find<RoomsController>();
  try {
    const storage = FlutterSecureStorage(aOptions: androidOptions);

    String? livekitToken = await storage.read(key: "createdRoomAdminToken");
+   if (livekitToken == null) {
+     Get.snackbar("Error", "Missing admin token. Room not deleted.");
+     return;
+   }
-   if (livekitToken != null) {
-     await apiService.deleteRoom(roomId, livekitToken);
-   }
+   await apiService.deleteRoom(roomId, livekitToken);
  } catch (e) {
-   print("Error deleting room: $e");
+   Get.snackbar("Error", "Failed to delete room: $e");
+   return;
  }

  DocumentList participantDocsRef = await roomsController.databases
      .listDocuments(
        databaseId: masterDatabaseId,
        collectionId: participantsCollectionId,
        queries: [
          Query.equal('roomId', [roomId]),
        ],
      );

  for (var document in participantDocsRef.documents) {
    await roomsController.databases.deleteDocument(
      databaseId: masterDatabaseId,
      collectionId: participantsCollectionId,
      documentId: document.$id,
    );
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
const storage = FlutterSecureStorage(aOptions: androidOptions);
// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
await apiService.deleteRoom(roomId, livekitToken!);
// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
if (livekitToken != null) {
await apiService.deleteRoom(roomId, livekitToken);
}
} catch (e) {
print("Error deleting room: $e");
}
try {
const storage = FlutterSecureStorage(aOptions: androidOptions);
// Delete room on livekit and roomdoc on appwrite
String? livekitToken = await storage.read(key: "createdRoomAdminToken");
if (livekitToken == null) {
Get.snackbar("Error", "Missing admin token. Room not deleted.");
return;
}
await apiService.deleteRoom(roomId, livekitToken);
} catch (e) {
Get.snackbar("Error", "Failed to delete room: $e");
return;
}
🤖 Prompt for AI Agents
In `@lib/services/room_service.dart` around lines 194 - 204, The Appwrite
participant cleanup must only run after a successful LiveKit deletion: in the
function using FlutterSecureStorage (storage) read the "createdRoomAdminToken"
into livekitToken and if livekitToken == null return early (do not proceed),
then call await apiService.deleteRoom(roomId, livekitToken) and if that call
throws let the exception bubble (or rethrow) instead of catching and continuing;
only after deleteRoom completes successfully continue with Appwrite
participant/document deletion logic so Appwrite cleanup is skipped whenever the
LiveKit deletion is skipped or fails.

Comment on lines +5 to +13
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:get/get.dart';
import 'package:whisper_flutter_new/whisper_flutter_new.dart';

const androidOptions = AndroidOptions(
encryptedSharedPreferences: true,
migrateOnAlgorithmChange: true,
resetOnError: true,
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the file and its context
cat -n lib/utils/constants.dart

Repository: AOSSIE-Org/Resonate

Length of output: 6082


🏁 Script executed:

# Search for any comments or documentation about this setting
rg -i "resetOnError\|android.*options" --type dart -B 3 -A 3

Repository: AOSSIE-Org/Resonate

Length of output: 45


🏁 Script executed:

# Check git history for this file to understand the intent
git log --oneline lib/utils/constants.dart | head -10

Repository: AOSSIE-Org/Resonate

Length of output: 114


🏁 Script executed:

# Search for other uses of AndroidOptions in the codebase
rg "AndroidOptions" --type dart

Repository: AOSSIE-Org/Resonate

Length of output: 126


🌐 Web query:

flutter_secure_storage AndroidOptions resetOnError behavior documentation

💡 Result:

In flutter_secure_storage, AndroidOptions.resetOnError controls whether the plugin should wipe its stored data (and re-initialize its crypto/material) when it detects an Android keystore/crypto error that would otherwise leave reads/writes permanently failing.

  • What it does: “When an error is detected, automatically reset all data … [and] will PERMANENTLY erase the data when an error occurs.” (AndroidOptions API docs) [1]
  • Default behavior (v10+): resetOnError now defaults to true (and the changelog explains this is because most such errors are “unrecoverable due to key storage problems”; you can still disable it with resetOnError: false). [2][1]
  • Why it exists: It’s meant to recover from common Android KeyStore / key-unwrapping / bad-decrypt failure modes where the app otherwise gets stuck erroring until the user clears app data. [3][2]

Implication: If resetOnError: true, you should assume that any keystore corruption / backup-restore mismatch / cipher/key mismatch can trigger a full secure-storage wipe on the device. [1][2]

Sources:
[1] AndroidOptions API docs (resetOnError default + meaning) https://pub.dev/documentation/flutter_secure_storage/latest/flutter_secure_storage/AndroidOptions-class.html
[2] Package changelog (resetOnError now automatically true / rationale) https://pub.dev/packages/flutter_secure_storage/changelog
[3] Example keystore failure report (illustrates the class of errors) juliansteenbakker/flutter_secure_storage#933


resetOnError: true wipes secure storage on crypto errors—justify or adjust.

This is documented behavior in flutter_secure_storage v10+: when enabled, the plugin clears all stored data if it detects an unrecoverable Android KeyStore or crypto error. While this helps recover from permanent failure states, it means tokens, credentials, and preferences will be lost if keystore corruption or backup-restore mismatches occur. Either add a comment explaining why this data-loss risk is acceptable, or set resetOnError: false and handle migration errors explicitly.

🤖 Prompt for AI Agents
In `@lib/utils/constants.dart` around lines 5 - 13, The AndroidOptions constant
androidOptions currently sets resetOnError: true which will wipe
flutter_secure_storage on unrecoverable crypto/KeyStore errors; change this to
resetOnError: false and add explicit migration/error handling where secure
storage is read (or, alternatively, if you intentionally accept data loss, add a
clear comment next to the AndroidOptions/androidOptions declaration documenting
why wiping is acceptable and the expected failure/recovery policy). Update
references to AndroidOptions/androidOptions usage sites to handle and surface
migration/crypto errors so the app can fallback or prompt re-authentication
instead of silently losing data.

- Update app_links from 6.4.1 to 7.0.0
- Update flutter_secure_storage from 9.2.4 to 10.0.0
- Update google_fonts from 6.3.2 to 8.0.0
- Update 69+ transitive dependencies

This update addresses security vulnerabilities and ensures compatibility with latest Flutter/Dart versions.
- Set Android minSdk to 23 in build.gradle.kts
- Use explicitly configured AndroidOptions with encryptedSharedPreferences
- Add error handling (try-catch) for all secure storage operations
- Centralize AndroidOptions configuration in constants.dart
@Muneerali199 Muneerali199 changed the base branch from master to dev January 25, 2026 14:25
@github-actions
Copy link
Contributor

PR Closed - Thank You, @Muneerali199!

  • If this PR was merged: Congratulations! Your contribution is now part of the project. 🚀
  • If this PR was closed without merging: Don’t worry! You can always improve it and submit again. 💪

We appreciate your effort and look forward to more contributions from you! 🤝

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant