diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7eb3709 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,114 @@ +# Flutter/Dart related +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ +*.lock.json +.metadata + +# Android related +android/.gradle/ +android/app/build/ +android/gradle/ +android/.idea/ +android/local.properties +android/key.properties +android/app/release/ +android/app/debug/ +android/captures/ +android/*.iml +*.jks +*.keystore +*.p12 +google-services.json + +# iOS related +ios/Pods/ +ios/.symlinks/ +ios/Flutter/Flutter.framework +ios/Flutter/Flutter.podspec +ios/.generated/ +ios/Runner.xcworkspace/ +ios/Runner.xcodeproj/xcuserdata/ +ios/Runner.xcodeproj/project.xcworkspace/xcuserdata/ +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 +*.xcuserstate +xcuserdata/ +DerivedData/ +*.mobileprovision +*.cer +*.p12 +GoogleService-Info.plist + +# IDE related +.idea/ +.vscode/ +*.swp +*.swo +*~ +.DS_Store +Thumbs.db +desktop.ini + +# Git +.git/ +.gitignore +.gitattributes +.github/ + +# CI/CD +.gitlab-ci.yml +.circleci/ +.travis.yml +azure-pipelines.yml + +# Testing and coverage +coverage/ +test/ +integration_test/ +.test_coverage/ +*.lcov +*.info + +# Documentation +README.md +README*.md +LICENSE +CHANGELOG.md +docs/ +CONTRIBUTING.md + +# Docker files +Dockerfile +Dockerfile.* +.dockerignore +docker-compose.yml +docker-compose.*.yml + +# Local configurations +.env +.env.* +.env.local +.env.*.local +*.log +*.log.* + +# Temporary files +*.tmp +*.temp +*.bak +*.swp +*~ + +# Firebase +firebase.json +.firebaserc +firestore.rules +firestore.indexes.json +storage.rules diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..34a1348 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,218 @@ +name: Flutter CI/CD Pipeline + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + workflow_dispatch: + +env: + FLUTTER_VERSION: '3.38.4' + ANDROID_SDK_VERSION: '35' + +jobs: + # ========================================== + # Job 1: Code Quality & Analysis + # ========================================== + analyze: + name: Code Analysis + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.FLUTTER_VERSION }} + channel: 'stable' + cache: true + + - name: Create fake firebase_options.dart + run: | + mkdir -p lib + cat < lib/firebase_options.dart + // ignore_for_file: type=lint + import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; + class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) throw UnsupportedError('Web not configured'); + switch (defaultTargetPlatform) { + case TargetPlatform.android: return android; + case TargetPlatform.iOS: return ios; + default: throw UnsupportedError('Platform not configured'); + } + } + static const FirebaseOptions android = FirebaseOptions(apiKey: 'fake', appId: 'fake', messagingSenderId: 'fake', projectId: 'fake', storageBucket: 'fake'); + static const FirebaseOptions ios = FirebaseOptions(apiKey: 'fake', appId: 'fake', messagingSenderId: 'fake', projectId: 'fake', storageBucket: 'fake', iosBundleId: 'fake'); + } + EOF + + - name: Get dependencies + run: flutter pub get + + - name: Run build_runner + run: dart run build_runner build --delete-conflicting-outputs + + - name: Format generated code + run: dart format . + + - name: Verify formatting + run: dart format --set-exit-if-changed lib/ test/ + continue-on-error: false + + - name: Analyze code + run: flutter analyze --fatal-infos + + - name: Run tests + run: flutter test --coverage || echo "⚠️ No tests found" + + - name: Upload coverage to artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: code-coverage + path: coverage/lcov.info + if-no-files-found: ignore + retention-days: 7 + + # ========================================== + # Job 2: Android Build (Docker) + # ========================================== + build-android: + name: Build Android APK + runs-on: ubuntu-latest + needs: analyze + timeout-minutes: 60 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Create mock configuration files + run: | + mkdir -p lib + # firebase_options.dart + echo "import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; class DefaultFirebaseOptions { static FirebaseOptions get currentPlatform { if (kIsWeb) throw UnsupportedError('Web not configured'); switch (defaultTargetPlatform) { case TargetPlatform.android: return android; case TargetPlatform.iOS: return ios; default: throw UnsupportedError('Platform not configured'); } } static const FirebaseOptions android = FirebaseOptions(apiKey: 'fake', appId: 'fake', messagingSenderId: 'fake', projectId: 'fake', storageBucket: 'fake'); static const FirebaseOptions ios = FirebaseOptions(apiKey: 'fake', appId: 'fake', messagingSenderId: 'fake', projectId: 'fake', storageBucket: 'fake', iosBundleId: 'fake'); }" > lib/firebase_options.dart + # google-services.json + echo '{"project_info":{"project_number":"123","project_id":"fake","storage_bucket":"fake"},"client":[{"client_info":{"mobilesdk_app_id":"1:123:android:123","android_client_info":{"package_name":"com.flutter.starter.template.flutter_starter_template"}},"api_key":[{"current_key":"fake"}]}]}' > android/app/google-services.json + + - name: Build Docker image + id: build + uses: docker/build-push-action@v5 + with: + context: . + push: false + load: true + tags: flutter-build:latest + build-args: | + BUILD_DATE=${{ github.event.repository.updated_at }} + VCS_REF=${{ github.sha }} + FLUTTER_VERSION=${{ env.FLUTTER_VERSION }} + ANDROID_SDK_VERSION=${{ env.ANDROID_SDK_VERSION }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Extract APK + run: | + docker create --name temp flutter-build:latest + mkdir -p apk-output + docker cp temp:/artifacts/. apk-output/ + docker rm temp + ls -lh apk-output/ + + - name: Upload Android APK artifacts + uses: actions/upload-artifact@v4 + with: + name: android-apk-${{ github.sha }} + path: apk-output/*.apk + retention-days: 30 + compression-level: 0 + + - name: Generate Summary + run: | + echo "## 🤖 Android APK Build Results" >> $GITHUB_STEP_SUMMARY + echo "| Architecture | File | Size |" >> $GITHUB_STEP_SUMMARY + echo "|--------------|----------|------|" >> $GITHUB_STEP_SUMMARY + for apk in apk-output/*.apk; do + name=$(basename "$apk") + size=$(du -h "$apk" | cut -f1) + arch="Universal" + if [[ "$name" == *"arm64"* ]]; then arch="ARM64"; fi + if [[ "$name" == *"armeabi"* ]]; then arch="ARMv7"; fi + if [[ "$name" == *"x86_64"* ]]; then arch="x86_64"; fi + echo "| $arch | \`$name\` | $size |" >> $GITHUB_STEP_SUMMARY + done + + # ========================================== + # Job 3: iOS Build (macOS runner) + # ========================================== + build-ios: + name: Build iOS IPA + runs-on: macos-latest + needs: analyze + timeout-minutes: 45 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.FLUTTER_VERSION }} + channel: 'stable' + cache: true + + - name: Create mock configuration files + run: | + mkdir -p lib ios/Runner + # Create firebase_options.dart + echo "import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; class DefaultFirebaseOptions { static FirebaseOptions get currentPlatform { if (kIsWeb) throw UnsupportedError('Web not configured'); switch (defaultTargetPlatform) { case TargetPlatform.android: return android; case TargetPlatform.iOS: return ios; default: throw UnsupportedError('Platform not configured'); } } static const FirebaseOptions android = FirebaseOptions(apiKey: 'fake', appId: 'fake', messagingSenderId: 'fake', projectId: 'fake', storageBucket: 'fake'); static const FirebaseOptions ios = FirebaseOptions(apiKey: 'fake', appId: 'fake', messagingSenderId: 'fake', projectId: 'fake', storageBucket: 'fake', iosBundleId: 'fake'); }" > lib/firebase_options.dart + # Create GoogleService-Info.plist + echo 'API_KEYfakeGCM_SENDER_ID123PLIST_VERSION1BUNDLE_IDcom.flutter.starter.template.flutterStarterTemplatePROJECT_IDfakeSTORAGE_BUCKETfakeIS_ADS_ENABLEDIS_ANALYTICS_ENABLEDIS_APPINVITE_ENABLEDIS_GCM_ENABLEDIS_SIGNIN_ENABLEDGOOGLE_APP_ID1:123:ios:123' > ios/Runner/GoogleService-Info.plist + + - name: Get dependencies + run: flutter pub get + + - name: Install Pods + run: | + cd ios + rm -rf Pods Podfile.lock + pod install --repo-update + + - name: Build iOS app + run: | + flutter build ios --release --no-codesign --build-number=${{ github.run_number }} + + - name: Create IPA + run: | + mkdir -p Payload + cp -R build/ios/iphoneos/Runner.app Payload/ + IPA_NAME="flutter-starter-ios-${{ github.run_number }}-unsigned.ipa" + zip -r "$IPA_NAME" Payload + rm -rf Payload + + - name: Upload iOS IPA artifact + uses: actions/upload-artifact@v4 + with: + name: ios-ipa-${{ github.sha }} + path: "*.ipa" + retention-days: 30 + compression-level: 0 + + - name: Generate Summary + run: | + echo "## 🍎 iOS IPA Build Results" >> $GITHUB_STEP_SUMMARY + echo "| File | Size |" >> $GITHUB_STEP_SUMMARY + echo "|------|------|" >> $GITHUB_STEP_SUMMARY + for ipa in *.ipa; do + size=$(du -h "$ipa" | cut -f1) + echo "| \`$ipa\` | $size |" >> $GITHUB_STEP_SUMMARY + done + echo "⚠️ Unsigned IPA for testing only." >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore index d540810..c539165 100644 --- a/.gitignore +++ b/.gitignore @@ -59,9 +59,22 @@ linked_*.ds unlinked.ds unlinked_spec.ds +# Build Runner generated +*.g.dart +*.mocks.dart + # Firebase related firebase_options.dart +# Docker related +*.img +*.tar +*.tar.gz + +# APK related +*.apk +apk-output/ + # Symbolication related app.*.symbols @@ -130,4 +143,4 @@ ios/Runner/GoogleService-Info.plist android/app/google-services.json # Generated localization -lib/core/localization/generated/ \ No newline at end of file +lib/core/localization/generated/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cbd39b..f2e3dd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added DI-independent fallback error handler inside runZonedGuarded to ensure reliable error reporting even if DI or Firebase are not ready. - Added unified analytics architecture with `Firebase Analytics` integration, debug logging, and automatic screen view tracking via `AnalyticsRouteObserver`. - Added `AppLoggerMixin` for convenient logger access in Bloc/Cubit +- **CI/CD**: Complete automated build pipeline with GitHub Actions + - Multi-stage Dockerfile with Flutter 3.38.4 and Android SDK 35 + - Support for split APK by ABI (armeabi-v7a, arm64-v8a, x86_64) + - `.dockerignore` for optimized build context + - GitHub Actions workflow: code analysis, Android (Docker + DockerHub), iOS (macOS runner) + - Automated quality checks, artifact uploads, and build summaries ### Changed diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4b784a6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,180 @@ +# ========================================== +# Global ARGs +# ========================================== +ARG TARGETPLATFORM=linux/amd64 +ARG FLUTTER_VERSION=3.38.4 +ARG ANDROID_SDK_VERSION=35 +ARG ANDROID_BUILD_TOOLS_VERSION=35.0.0 +ARG CMDLINE_TOOLS_VERSION=13114758 + + +# ========================================== +# Stage 1: Builder - Android APK build +# ========================================== +FROM --platform=$TARGETPLATFORM ubuntu:22.04 AS builder + + +# Use global ARGs +ARG FLUTTER_VERSION +ARG ANDROID_SDK_VERSION +ARG ANDROID_BUILD_TOOLS_VERSION +ARG CMDLINE_TOOLS_VERSION + + +# Disable interactive prompts +ENV DEBIAN_FRONTEND=noninteractive + + +# Install required dependencies +RUN apt-get update && apt-get install -y \ + curl \ + git \ + unzip \ + xz-utils \ + zip \ + libglu1-mesa \ + openjdk-17-jdk \ + wget \ + ca-certificates \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + + +# Detect actual Java path and create symlink if needed +RUN REAL_JAVA=$(dirname $(dirname $(readlink -f $(which javac)))) && \ + echo "Real Java path: ${REAL_JAVA}" && \ + if [ "${REAL_JAVA}" != "/usr/lib/jvm/java-17-openjdk-amd64" ]; then \ + mkdir -p /usr/lib/jvm && \ + ln -sf ${REAL_JAVA} /usr/lib/jvm/java-17-openjdk-amd64; \ + fi + + +# Set JAVA_HOME via ENV (works for all subsequent RUN commands) +ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 +ENV PATH=$JAVA_HOME/bin:$PATH + + +# Verify that Java is working +RUN java -version && javac -version && \ + echo "JAVA_HOME is set to: ${JAVA_HOME}" && \ + ls -la ${JAVA_HOME}/bin/java + + +# Configure Android SDK +ENV ANDROID_SDK_ROOT=/opt/android-sdk +ENV ANDROID_HOME=$ANDROID_SDK_ROOT +ENV PATH=$PATH:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools:$ANDROID_SDK_ROOT/build-tools/${ANDROID_BUILD_TOOLS_VERSION} + + +# Create directory for Android SDK +RUN mkdir -p $ANDROID_SDK_ROOT/cmdline-tools + + +# Download and install Android Command Line Tools +RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-${CMDLINE_TOOLS_VERSION}_latest.zip -O /tmp/cmdline-tools.zip && \ + unzip -q /tmp/cmdline-tools.zip -d $ANDROID_SDK_ROOT/cmdline-tools && \ + mv $ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools $ANDROID_SDK_ROOT/cmdline-tools/latest && \ + rm /tmp/cmdline-tools.zip + + +# Install required Android SDK components (JAVA_HOME already set via ENV) +RUN echo "Current JAVA_HOME: ${JAVA_HOME}" && \ + yes | sdkmanager --licenses && \ + sdkmanager --install \ + "platform-tools" \ + "platforms;android-${ANDROID_SDK_VERSION}" \ + "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \ + "cmdline-tools;latest" + + +# Download Flutter SDK (release archive instead of git clone for speed) +RUN wget -q https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz -O /tmp/flutter.tar.xz && \ + tar xf /tmp/flutter.tar.xz -C /opt && \ + rm /tmp/flutter.tar.xz + + +# Configure environment variables for Flutter +ENV FLUTTER_ROOT=/opt/flutter +ENV PATH="${FLUTTER_ROOT}/bin:${FLUTTER_ROOT}/bin/cache/dart-sdk/bin:$PATH" +ENV PUB_CACHE=/root/.pub-cache + + +# Fix Git safe.directory warning +RUN git config --global --add safe.directory /opt/flutter && \ + git config --global --add safe.directory "${FLUTTER_ROOT}" + + +# Initial Flutter setup +RUN flutter doctor -v && \ + flutter config --no-analytics && \ + flutter config --android-sdk $ANDROID_SDK_ROOT && \ + flutter precache --android --no-ios --no-web + + +# Create directories for caching +RUN mkdir -p $PUB_CACHE && \ + mkdir -p /root/.gradle + + +# Set working directory +WORKDIR /app + + +# Copy dependency files to leverage layer caching +COPY pubspec.yaml pubspec.lock ./ + + +# Install dependencies +RUN flutter pub get + + +# Copy entire project +COPY . . + + +# Build Android APK in release mode +RUN flutter build apk --release --split-per-abi --no-tree-shake-icons + + +# Verify that the build succeeded +RUN test -f /app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk || \ + test -f /app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk || \ + (echo "ERROR: APK files not found!" && exit 1) + + +# ========================================== +# Stage 2: Runtime - Artifact storage +# ========================================== +FROM alpine:latest AS runtime + + +# Set image metadata +ARG FLUTTER_VERSION +ARG BUILD_DATE +ARG VCS_REF + + +LABEL maintainer="cowboycloud@icloud.com" \ + description="Flutter Android APK Build Artifacts" \ + version="1.0.0" \ + flutter.version="${FLUTTER_VERSION}" \ + org.opencontainers.image.created="${BUILD_DATE}" \ + org.opencontainers.image.revision="${VCS_REF}" \ + org.opencontainers.image.title="Flutter Starter Template Android Build" \ + org.opencontainers.image.description="Production-ready Android APK artifacts" + + +# Create directory for APKs +RUN mkdir -p /artifacts + + +# Copy built APKs from builder stage +COPY --from=builder /app/build/app/outputs/flutter-apk/*.apk /artifacts/ + + +# Set working directory +WORKDIR /artifacts + + +# Default command - list files with sizes +CMD ["ls", "-lh"] diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 86ec58e..0439783 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -201,7 +201,6 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3D0E01DF18316EDF773EAB0D /* [CP] Embed Pods Frameworks */, - 05D396F55CC39F0934932997 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */, ); buildRules = ( ); @@ -274,24 +273,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 05D396F55CC39F0934932997 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\""; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\n#!/bin/bash\nPATH=\"${PATH}:$FLUTTER_ROOT/bin:${PUB_CACHE}/bin:$HOME/.pub-cache/bin\"\n\nif [ -z \"$PODS_ROOT\" ] || [ ! -d \"$PODS_ROOT/FirebaseCrashlytics\" ]; then\n # Cannot use \"BUILD_DIR%/Build/*\" as per Firebase documentation, it points to \"flutter-project/build/ios/*\" path which doesn't have run script\n DERIVED_DATA_PATH=$(echo \"$BUILD_ROOT\" | sed -E 's|(.*DerivedData/[^/]+).*|\\1|')\n PATH_TO_CRASHLYTICS_UPLOAD_SCRIPT=\"${DERIVED_DATA_PATH}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run\"\nelse\n PATH_TO_CRASHLYTICS_UPLOAD_SCRIPT=\"$PODS_ROOT/FirebaseCrashlytics/run\"\nfi\n\n# Command to upload symbols script used to upload symbols to Firebase server\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=\"$PATH_TO_CRASHLYTICS_UPLOAD_SCRIPT\" --platform=ios --apple-project-path=\"${SRCROOT}\" --env-platform-name=\"${PLATFORM_NAME}\" --env-configuration=\"${CONFIGURATION}\" --env-project-dir=\"${PROJECT_DIR}\" --env-built-products-dir=\"${BUILT_PRODUCTS_DIR}\" --env-dwarf-dsym-folder-path=\"${DWARF_DSYM_FOLDER_PATH}\" --env-dwarf-dsym-file-name=\"${DWARF_DSYM_FILE_NAME}\" --env-infoplist-path=\"${INFOPLIST_PATH}\" --default-config=default\n"; - }; 1D144EDA24AD260BDCD8A5DC /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -360,10 +341,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -382,7 +367,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/test/core/router/analytics_route_onserver_test.mocks.dart b/test/core/router/analytics_route_onserver_test.mocks.dart deleted file mode 100644 index 6968f91..0000000 --- a/test/core/router/analytics_route_onserver_test.mocks.dart +++ /dev/null @@ -1,47 +0,0 @@ -// Mocks generated by Mockito 5.4.6 from annotations -// in flutter_starter_template/test/core/router/analytics_route_onserver_test.dart. -// Do not manually edit this file. - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i3; - -import 'package:flutter_starter_template/core/utils/analytics/app_analytics.dart' - as _i2; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: deprecated_member_use -// ignore_for_file: deprecated_member_use_from_same_package -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: must_be_immutable -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types -// ignore_for_file: subtype_of_sealed_class - -/// A class which mocks [AppAnalytics]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockAppAnalytics extends _i1.Mock implements _i2.AppAnalytics { - @override - _i3.Future logEvent(String? name, {Map? parameters}) => - (super.noSuchMethod( - Invocation.method(#logEvent, [name], {#parameters: parameters}), - returnValue: _i3.Future.value(), - returnValueForMissingStub: _i3.Future.value(), - ) - as _i3.Future); - - @override - _i3.Future logScreenView(String? screenName) => - (super.noSuchMethod( - Invocation.method(#logScreenView, [screenName]), - returnValue: _i3.Future.value(), - returnValueForMissingStub: _i3.Future.value(), - ) - as _i3.Future); -}