diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 45b6bec..59536a3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -30,3 +30,18 @@ updates: update-types: - "minor" - "patch" + + - package-ecosystem: "gradle" + directory: "/transcriberapp/android" + schedule: + interval: "weekly" + day: "monday" + time: "06:00" + timezone: "UTC" + groups: + android-deps: + patterns: + - "*" + update-types: + - "minor" + - "patch" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1ebe643..bc6a88e 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,26 +1,30 @@ ## Description - Summarize the changes and the intent. +- Explain the motivation and context. ## Type of change -- [ ] Bug fix -- [ ] Feature -- [ ] Refactor -- [ ] Chore/CI -- [ ] Documentation +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] Feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Refactor (code restructuring) +- [ ] Chore/CI (updating configurations, dependencies, etc.) +- [ ] Documentation update -## Testing +## Testing Checklist -- [ ] `flutter analyze` (or CI green) -- [ ] `dart format --set-exit-if-changed .` -- [ ] `flutter test` -- [ ] `flutter build apk --release` -- [ ] No breaking changes introduced +- [ ] `flutter analyze` passes locally +- [ ] `dart format --set-exit-if-changed .` passes locally +- [ ] `flutter test` passes locally +- [ ] New unit tests have been added to cover the changes (if applicable) +- [ ] `flutter build apk --release` succeeds locally without errors ## Screenshots (if UI changes) -If applicable, add screenshots or screen recordings. +| Before | After | +| ------ | ----- | +| [Screenshot] | [Screenshot] | ## Linked issue diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..4b5da4a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,60 @@ +name: Build Android + +on: + workflow_dispatch: + push: + branches: + - release/* + +jobs: + build_android: + runs-on: ubuntu-latest + defaults: + run: + working-directory: transcriberapp + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '21' + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + + - name: Install dependencies + run: flutter pub get + + - name: Cache Gradle + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('transcriberapp/android/**/*.gradle*', 'transcriberapp/android/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Build APK + run: flutter build apk --release + + - name: Build App Bundle + run: flutter build appbundle --release + + - name: Upload APK + uses: actions/upload-artifact@v4 + with: + name: release-apk + path: transcriberapp/build/app/outputs/flutter-apk/app-release.apk + + - name: Upload AAB + uses: actions/upload-artifact@v4 + with: + name: release-aab + path: transcriberapp/build/app/outputs/bundle/release/app-release.aab diff --git a/.github/workflows/flutter_ci.yml b/.github/workflows/ci.yml similarity index 54% rename from .github/workflows/flutter_ci.yml rename to .github/workflows/ci.yml index b76266f..79ab84f 100644 --- a/.github/workflows/flutter_ci.yml +++ b/.github/workflows/ci.yml @@ -2,11 +2,20 @@ name: Flutter CI on: push: - branches: [main] + branches: + - main + - develop pull_request: + branches: + - main + - develop + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - build: + build_and_test: runs-on: ubuntu-latest defaults: run: @@ -22,12 +31,11 @@ jobs: channel: stable - name: Cache pub dependencies - uses: actions/cache@v5 + uses: actions/cache@v4 with: path: | ~/.pub-cache - ~/.flutter-plugins - ~/.flutter-plugin-cache + transcriberapp/.dart_tool key: ${{ runner.os }}-pub-${{ hashFiles('transcriberapp/pubspec.lock') }} restore-keys: | ${{ runner.os }}-pub- @@ -35,14 +43,19 @@ jobs: - name: Install dependencies run: flutter pub get - - name: Analyze - run: flutter analyze - - name: Check formatting run: dart format --set-exit-if-changed . - - name: Run tests - run: flutter test + - name: Analyze + run: flutter analyze - - name: Build APK (release) - run: flutter build apk --release + - name: Run tests with coverage + run: flutter test --coverage + + - name: Check Code Coverage + uses: VeryGoodOpenSource/very_good_coverage@v3 + with: + path: transcriberapp/coverage/lcov.info + # Currently set to 0 to avoid breaking CI since there are no tests yet. + # Change to 80 when ready. + min_coverage: 0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..d6566b4 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,54 @@ +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '30 4 * * 1' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'java-kotlin' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '21' + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + + - name: Flutter build (for java-kotlin compilation) + run: | + cd transcriberapp + flutter pub get + flutter build apk --release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml new file mode 100644 index 0000000..3d98fd6 --- /dev/null +++ b/.github/workflows/commit-lint.yml @@ -0,0 +1,11 @@ +name: Lint Commit Messages +on: [pull_request] + +jobs: + commitlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: wagoid/commitlint-github-action@v6 diff --git a/.github/workflows/dependency_review.yml b/.github/workflows/dependency_review.yml new file mode 100644 index 0000000..4f5489e --- /dev/null +++ b/.github/workflows/dependency_review.yml @@ -0,0 +1,21 @@ +name: 'Dependency Review' +on: + pull_request: + branches: [ "main", "develop" ] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout repository' + uses: actions/checkout@v4 + + - name: 'Dependency Review' + uses: actions/dependency-review-action@v4 + with: + # Optional: Block PRs introducing dependencies with GPL/AGPL licenses + deny-licenses: GPL-1.0-or-later, GPL-2.0-or-later, GPL-3.0-or-later, AGPL-1.0-or-later, AGPL-3.0-or-later + fail-on-severity: high diff --git a/.github/workflows/dependency_staleness.yml b/.github/workflows/dependency_staleness.yml new file mode 100644 index 0000000..d62e5bc --- /dev/null +++ b/.github/workflows/dependency_staleness.yml @@ -0,0 +1,45 @@ +name: Dependency Staleness Check + +on: + schedule: + - cron: '0 5 * * 1' # Runs at 05:00 UTC on Mondays + workflow_dispatch: + +jobs: + check-staleness: + runs-on: ubuntu-latest + defaults: + run: + working-directory: transcriberapp + permissions: + issues: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + + - name: Install dependencies + run: flutter pub get + + - name: Check Outdated Packages + id: check_outdated + run: | + OUTDATED=$(flutter pub outdated) + echo "$OUTDATED" + + # We can create a simple check. If there are resolvable updates, we might want to flag them. + # Here we just output it to a file for the next step. + echo "$OUTDATED" > outdated_report.txt + + - name: Create Issue if highly outdated + uses: peter-evans/create-issue-from-file@v5 + if: success() + with: + title: "Weekly Dependency Staleness Report" + content-filepath: transcriberapp/outdated_report.txt + labels: "dependencies, maintenance" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6ee489a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,47 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + release: + runs-on: ubuntu-latest + defaults: + run: + working-directory: transcriberapp + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '21' + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + + - name: Install dependencies + run: flutter pub get + + - name: Build APK + run: flutter build apk --release + + - name: Build App Bundle + run: flutter build appbundle --release + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true + files: | + transcriberapp/build/app/outputs/flutter-apk/app-release.apk + transcriberapp/build/app/outputs/bundle/release/app-release.aab diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..1c533c0 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,6 @@ +# CODEOWNERS +# Use this file to require reviews from maintainers for specific directories or files. + +* @MabelMoncy +/transcriberapp/ @MabelMoncy +/android/ @MabelMoncy diff --git a/scripts/setup_git_hooks.sh b/scripts/setup_git_hooks.sh new file mode 100644 index 0000000..d361761 --- /dev/null +++ b/scripts/setup_git_hooks.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# script/setup_git_hooks.sh + +HOOKS_DIR=".git/hooks" +PRE_PUSH_HOOK="$HOOKS_DIR/pre-push" + +echo "Setting up pre-push git hook..." + +cat << 'EOF' > "$PRE_PUSH_HOOK" +#!/bin/bash +# Pre-push hook to run formatting and analysis + +echo "Running pre-push checks..." +cd transcriberapp || exit 1 + +echo "1. Checking formatting..." +dart format --set-exit-if-changed . +if [ $? -ne 0 ]; then + echo "❌ Code formatting issues found. Please run 'dart format .' and commit the changes." + exit 1 +fi + +echo "2. Running analyzer..." +flutter analyze +if [ $? -ne 0 ]; then + echo "❌ Analyzer found issues. Please fix them before pushing." + exit 1 +fi + +echo "✅ All checks passed. Pushing..." +exit 0 +EOF + +chmod +x "$PRE_PUSH_HOOK" +echo "✅ Git hooks configured successfully!" diff --git a/transcriberapp/analysis_options.yaml b/transcriberapp/analysis_options.yaml index f9b3034..3104462 100644 --- a/transcriberapp/analysis_options.yaml +++ b/transcriberapp/analysis_options.yaml @@ -1 +1,18 @@ include: package:flutter_lints/flutter.yaml + +linter: + rules: + - avoid_print + - prefer_const_constructors + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + - prefer_final_locals + - prefer_is_empty + - prefer_is_not_empty + - camel_case_types + - library_names + - avoid_empty_else + - cancel_subscriptions + - close_sinks + - always_declare_return_types + - annotate_overrides diff --git a/transcriberapp/android/gradle.properties b/transcriberapp/android/gradle.properties index f018a61..475a628 100644 --- a/transcriberapp/android/gradle.properties +++ b/transcriberapp/android/gradle.properties @@ -1,3 +1,7 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false diff --git a/transcriberapp/android/gradle/wrapper/gradle-wrapper.properties b/transcriberapp/android/gradle/wrapper/gradle-wrapper.properties index ac3b479..f587a47 100644 --- a/transcriberapp/android/gradle/wrapper/gradle-wrapper.properties +++ b/transcriberapp/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-all.zip diff --git a/transcriberapp/android/settings.gradle.kts b/transcriberapp/android/settings.gradle.kts index fb605bc..ca7fe06 100644 --- a/transcriberapp/android/settings.gradle.kts +++ b/transcriberapp/android/settings.gradle.kts @@ -19,8 +19,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.9.1" apply false - id("org.jetbrains.kotlin.android") version "2.1.0" apply false + id("com.android.application") version "8.11.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") diff --git a/transcriberapp/lib/models/app_state.dart b/transcriberapp/lib/models/app_state.dart index bafc8f9..4284ce4 100644 --- a/transcriberapp/lib/models/app_state.dart +++ b/transcriberapp/lib/models/app_state.dart @@ -1,10 +1,8 @@ enum AppState { initial, - fileShared, - uploading, transcribing, success, error, liveRecording, - liveTranscribing + liveTranscribing, } diff --git a/transcriberapp/lib/screens/onboarding_screen.dart b/transcriberapp/lib/screens/onboarding_screen.dart index c4acf5c..bddee3a 100644 --- a/transcriberapp/lib/screens/onboarding_screen.dart +++ b/transcriberapp/lib/screens/onboarding_screen.dart @@ -17,10 +17,10 @@ class _OnboardingScreenState extends State { Future _submitKey() async { final key = _keyController.text.trim(); - if (key.length < 10 || !key.startsWith("AIza")) { + if (key.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text("Invalid Key. It must start with 'AIza'"), + content: Text("Please paste your Gemini API Key"), backgroundColor: Colors.redAccent ), ); @@ -183,7 +183,7 @@ class _OnboardingScreenState extends State { style: TextStyle(color: textColor), decoration: InputDecoration( labelText: "Paste API Key Here", - hintText: "AIza...", + hintText: "Paste your key here", hintStyle: TextStyle(color: isDark ? Colors.grey.shade600 : Colors.grey.shade400), labelStyle: const TextStyle(color: Colors.blueAccent), prefixIcon: const Icon(Icons.vpn_key, color: Colors.blueAccent), diff --git a/transcriberapp/lib/services/gemini_service.dart b/transcriberapp/lib/services/gemini_service.dart index 84ee051..8ea7d9e 100644 --- a/transcriberapp/lib/services/gemini_service.dart +++ b/transcriberapp/lib/services/gemini_service.dart @@ -1,86 +1,100 @@ -import 'dart:io'; -import 'package:google_generative_ai/google_generative_ai.dart'; -import 'package:mime/mime.dart'; +import 'dart:io' as io; +import 'package:googleai_dart/googleai_dart.dart'; +import 'package:mime/mime.dart'; import 'api_key_manager.dart'; class GeminiService { final ApiKeyManager _keyManager = ApiKeyManager(); - // Models - static const String _primaryModel = "gemini-2.5-pro"; - static const String _secondaryModel = "gemini-2.5-flash"; - static const String _tertiaryModel = "gemini-2.5-flash-lite"; + // Ordered fallback chain: try each model in sequence. + // 1. gemini-2.5-flash — fast, capable primary model + // 2. gemini-3.5-flash — latest generation backup + // 3. gemini-3.1-flash-lite — lightweight final fallback + static const List _models = [ + 'gemini-2.5-flash', + 'gemini-3.5-flash', + 'gemini-3.1-flash-lite', + ]; - Future transcribeAudio(File audioFile) async { + /// Single entry point for the UI — takes a file, returns transcribed text. + /// Handles the entire model fallback chain internally. + Future transcribeAudio(io.File audioFile) async { final apiKey = await _keyManager.getApiKey(); - - if (apiKey == null || apiKey.isEmpty) { - throw Exception("API Key missing. Please restart the app and setup your key."); + if (apiKey == null || apiKey.trim().isEmpty) { + throw Exception( + 'API Key missing. Please restart the app and set up your key.', + ); } - // Smart Mime Type - String? mimeType = lookupMimeType(audioFile.path); - if (audioFile.path.endsWith('.opus')) { - mimeType = 'audio/ogg'; - } else if (audioFile.path.endsWith('.m4a')) { - mimeType = 'audio/mp4'; - } - mimeType ??= 'audio/mp4'; - + // Resolve MIME type for common WhatsApp audio formats + final mimeType = _resolveMimeType(audioFile.path); final bytes = await audioFile.readAsBytes(); - - final content = [ - Content.multi([ - // Simple prompt: Allows the AI to handle grammar/summarization naturally - TextPart("Transcribe this audio."), - DataPart(mimeType, bytes), - ]) - ]; - // Fallback System + // Build the content payload once — reused across all model attempts + final request = GenerateContentRequest( + contents: [ + Content.user([ + Part.text('Transcribe this audio.'), + Part.bytes(bytes, mimeType), + ]), + ], + generationConfig: const GenerationConfig( + temperature: 0, + candidateCount: 1, + ), + ); + + // Create one client with the user's API key + final client = GoogleAIClient( + config: GoogleAIConfig.googleAI( + authProvider: ApiKeyProvider(apiKey), + ), + ); + try { - print("🚀 Level 1: $_primaryModel"); - return await _tryTranscribe(apiKey, _primaryModel, content); - } catch (e) { - print("⚠️ $_primaryModel Failed: $e"); - // Backoff: If quota/rate-limit error, give the API a 2-second - // breathing window before hammering the next tier. - final isQuotaError = e.toString().contains("Quota exceeded") || - e.toString().contains("429"); - if (isQuotaError) { - print("⏳ Quota hit — waiting 2s before Level 2..."); - await Future.delayed(const Duration(seconds: 2)); - } - try { - print("⚡ Level 2: $_secondaryModel"); - return await _tryTranscribe(apiKey, _secondaryModel, content); - } catch (e2) { - print("⚠️ $_secondaryModel Failed: $e2"); + Exception? lastError; + + for (final modelName in _models) { try { - print("🛡️ Level 3: $_tertiaryModel"); - return await _tryTranscribe(apiKey, _tertiaryModel, content); - } catch (e3) { - print("⚠️ $_tertiaryModel Failed: $e3"); - throw Exception("Transcription failed. Please check internet/key."); + print('🚀 Trying model: $modelName'); + final response = await client.models.generateContent( + model: modelName, + request: request, + ); + final text = response.text; + if (text == null || text.isEmpty) { + throw Exception('Empty response from $modelName'); + } + return text; // Success — exit immediately + } on RateLimitException catch (e) { + // Quota / rate-limit hit — wait before trying the next model + print('⏳ Rate limit on $modelName — waiting 2s...'); + lastError = e; + await Future.delayed(const Duration(seconds: 2)); + } on ApiException catch (e) { + // Region error, safety block, or other API-level failure + print('⚠️ API error on $modelName: ${e.message}'); + lastError = e; + } catch (e) { + // Unexpected error — log and try next model + print('⚠️ $modelName failed: $e'); + lastError = e is Exception ? e : Exception(e.toString()); } } + + // All models exhausted + throw lastError ?? + Exception('Transcription failed. Please check internet/key.'); + } finally { + client.close(); } } - Future _tryTranscribe(String key, String modelName, List content) async { - final model = GenerativeModel( - model: modelName, - apiKey: key, - // We keep temperature 0 to prevent hallucinations (making up fake text), - // but we removed the strict prompt constraints so it flows naturally. - generationConfig: GenerationConfig( - temperature: 0, - candidateCount: 1, - ), - ); - - final response = await model.generateContent(content); - if (response.text == null) throw Exception("Empty response from AI"); - return response.text!; + /// Resolves MIME type for common WhatsApp audio formats. + /// Falls back to 'audio/mp4' if the type cannot be determined. + String _resolveMimeType(String filePath) { + if (filePath.endsWith('.opus')) return 'audio/ogg'; + if (filePath.endsWith('.m4a')) return 'audio/mp4'; + return lookupMimeType(filePath) ?? 'audio/mp4'; } } \ No newline at end of file diff --git a/transcriberapp/macos/Flutter/GeneratedPluginRegistrant.swift b/transcriberapp/macos/Flutter/GeneratedPluginRegistrant.swift index 9f41b72..a11f437 100644 --- a/transcriberapp/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/transcriberapp/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,24 +7,18 @@ import Foundation import audioplayers_darwin import flutter_secure_storage_darwin -import package_info_plus import record_macos import share_plus import shared_preferences_foundation import sqflite_darwin import url_launcher_macos -import video_player_avfoundation -import wakelock_plus func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) - FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) - FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) - WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) } diff --git a/transcriberapp/pubspec.lock b/transcriberapp/pubspec.lock index 535f8d7..985e43a 100644 --- a/transcriberapp/pubspec.lock +++ b/transcriberapp/pubspec.lock @@ -105,14 +105,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.4" - chewie: - dependency: "direct main" - description: - name: chewie - sha256: "5b8f00a9373252ddd2296d0d734b3b754380e6b4728ba848aff40e97fabad339" - url: "https://pub.dev" - source: hosted - version: "1.14.1" cli_util: dependency: transitive description: @@ -161,30 +153,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" - csslib: - dependency: transitive - description: - name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - cupertino_icons: - dependency: transitive - description: - name: cupertino_icons - sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" - url: "https://pub.dev" - source: hosted - version: "1.0.9" - dbus: - dependency: transitive - description: - name: dbus - sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 - url: "https://pub.dev" - source: hosted - version: "0.7.12" external_app_launcher: dependency: "direct main" description: @@ -238,14 +206,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_dotenv: - dependency: "direct main" - description: - name: flutter_dotenv - sha256: d41da11fb497314fbf89811ec30af02d1d898b47980a129f0a8c0a1720460ba2 - url: "https://pub.dev" - source: hosted - version: "6.0.1" flutter_launcher_icons: dependency: "direct dev" description: @@ -336,14 +296,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.0" - google_generative_ai: + googleai_dart: dependency: "direct main" description: - name: google_generative_ai - sha256: "71f613d0247968992ad87a0eb21650a566869757442ba55a31a81be6746e0d1f" + name: googleai_dart + sha256: "58c628b8b96ffff9d8a80e23ef7d2813ad38c0b48360a9c84e7234f15a8098de" url: "https://pub.dev" source: hosted - version: "0.4.7" + version: "9.0.0" hooks: dependency: transitive description: @@ -352,16 +312,8 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" - html: - dependency: transitive - description: - name: html - sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" - url: "https://pub.dev" - source: hosted - version: "0.15.6" http: - dependency: "direct main" + dependency: transitive description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" @@ -369,7 +321,7 @@ packages: source: hosted version: "1.6.0" http_parser: - dependency: "direct main" + dependency: transitive description: name: http_parser sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" @@ -448,14 +400,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.0" - logger: - dependency: transitive - description: - name: logger - sha256: "25aee487596a6257655a1e091ec2ae66bc30e7af663592cc3a27e6591e05035c" - url: "https://pub.dev" - source: hosted - version: "2.7.0" logging: dependency: transitive description: @@ -484,10 +428,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.0" mime: dependency: "direct main" description: @@ -504,14 +448,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.17.6" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" objective_c: dependency: transitive description: @@ -528,22 +464,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" - package_info_plus: - dependency: transitive - description: - name: package_info_plus - sha256: "4bf625947f6c7713ee242296a682e23e44823c09cf9d79e4f1238923c92db852" - url: "https://pub.dev" - source: hosted - version: "10.1.0" - package_info_plus_platform_interface: - dependency: transitive - description: - name: package_info_plus_platform_interface - sha256: db762cb2f4f25ee60fb6359773861b0f199e00b90d237bd85a76a1e806b46ef4 - url: "https://pub.dev" - source: hosted - version: "4.1.0" path: dependency: "direct main" description: @@ -680,14 +600,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.5.0" - provider: - dependency: transitive - description: - name: provider - sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" - url: "https://pub.dev" - source: hosted - version: "6.1.5+1" pub_semver: dependency: transitive description: @@ -769,14 +681,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.7" - rename: - dependency: "direct main" - description: - name: rename - sha256: da5f4d67f8c68f066ad04edfd6585495dbe595f2baf3b1999eb6af1805d79539 - url: "https://pub.dev" - source: hosted - version: "3.1.0" share_plus: dependency: "direct main" description: @@ -946,10 +850,10 @@ packages: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.11" typed_data: dependency: transitive description: @@ -1038,46 +942,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" - video_player: - dependency: "direct main" - description: - name: video_player - sha256: "48a7bdaa38a3d50ec10c78627abdbfad863fdf6f0d6e08c7c3c040cfd80ae36f" - url: "https://pub.dev" - source: hosted - version: "2.11.1" - video_player_android: - dependency: transitive - description: - name: video_player_android - sha256: "877a6c7ba772456077d7bfd71314629b3fe2b73733ce503fc77c3314d43a0ca0" - url: "https://pub.dev" - source: hosted - version: "2.9.5" - video_player_avfoundation: - dependency: transitive - description: - name: video_player_avfoundation - sha256: af0e5b8a7a4876fb37e7cc8cb2a011e82bb3ecfa45844ef672e32cb14a1f259e - url: "https://pub.dev" - source: hosted - version: "2.9.4" - video_player_platform_interface: - dependency: transitive - description: - name: video_player_platform_interface - sha256: "57c5d73173f76d801129d0531c2774052c5a7c11ccb962f1830630decd9f24ec" - url: "https://pub.dev" - source: hosted - version: "6.6.0" - video_player_web: - dependency: transitive - description: - name: video_player_web - sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb" - url: "https://pub.dev" - source: hosted - version: "2.4.0" vm_service: dependency: transitive description: @@ -1086,22 +950,6 @@ packages: url: "https://pub.dev" source: hosted version: "15.1.0" - wakelock_plus: - dependency: transitive - description: - name: wakelock_plus - sha256: "824c5bba0f800e86d32e57d3d1843c531f090005cc89d9a837933e6601093d53" - url: "https://pub.dev" - source: hosted - version: "1.6.1" - wakelock_plus_platform_interface: - dependency: transitive - description: - name: wakelock_plus_platform_interface - sha256: b13f99e992e7ae6a152e16c5559d3c07ff445b13330192662494e614ca3e7d7b - url: "https://pub.dev" - source: hosted - version: "1.5.1" web: dependency: transitive description: @@ -1110,6 +958,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" win32: dependency: transitive description: @@ -1143,5 +999,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.11.0 <4.0.0" + dart: ">=3.12.0 <4.0.0" flutter: ">=3.38.4" diff --git a/transcriberapp/pubspec.yaml b/transcriberapp/pubspec.yaml index d466d20..3ef828f 100644 --- a/transcriberapp/pubspec.yaml +++ b/transcriberapp/pubspec.yaml @@ -1,20 +1,20 @@ name: transcriberapp -description: "A serverlass AI Audio transcriber." +description: "A serverless AI Audio transcriber." publish_to: 'none' -version: 2.0.0 +version: 2.1.0 environment: - sdk: ^3.11.0 + sdk: ^3.12.0 dependencies: flutter: sdk: flutter - # --- NEW: Serverless AI & Storage --- - google_generative_ai: ^0.4.7 # The Gemini AI Engine - flutter_secure_storage: ^10.3.0 # Secure Vault for API Key - shared_preferences: ^2.5.5 # To track "First Time" launch - url_launcher: ^6.3.2 # To open the "Get API Key" link + # --- Serverless AI & Storage --- + googleai_dart: ^9.0.0 # Gemini AI Engine (replaces deprecated google_generative_ai) + flutter_secure_storage: ^10.3.0 # Secure Vault for API Key + shared_preferences: ^2.5.5 # To track "First Time" launch + url_launcher: ^6.3.2 # To open the "Get API Key" link receive_sharing_intent: @@ -26,16 +26,10 @@ dependencies: record: ^6.2.1 sqflite: ^2.4.2 path: ^1.9.1 - http: ^1.6.0 mime: ^2.0.0 - http_parser: ^4.1.2 - flutter_dotenv: ^6.0.1 - rename: ^3.1.0 intl: ^0.20.1 audioplayers: ^6.6.0 share_plus: ^13.1.0 - video_player: ^2.11.1 - chewie: ^1.14.1 google_fonts: ^8.1.0 external_app_launcher: ^4.0.3 diff --git a/transcriberapp/test/widget_test.dart b/transcriberapp/test/widget_test.dart new file mode 100644 index 0000000..aae5924 --- /dev/null +++ b/transcriberapp/test/widget_test.dart @@ -0,0 +1,7 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Baseline test to ensure test runner works', () { + expect(true, isTrue); + }); +}