### Dependency Injection Setup Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/architecture-feature-first/SKILL.md Illustrates how to set up dependencies using a service locator (e.g., get_it). This example registers services, repositories, and makes them available as singletons for the application. ```dart // In service_locator.dart — register dependencies at startup void setupDependencies() { final apiClient = ApiClient(); // Services final authService = AuthApiService(apiClient); final profileService = ProfileApiService(apiClient); // Repositories final authRepo = AuthRepository(authService); final profileRepo = ProfileRepository(profileService); // Register with your DI framework (get_it, provider, riverpod, etc.) getIt.registerSingleton(authRepo); getIt.registerSingleton(profileRepo); } ``` -------------------------------- ### Install FlutterFire CLI and Firebase Tools Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/flutterfire-configure/SKILL.md Install the necessary command-line tools for FlutterFire and Firebase. Ensure you are logged into Firebase. ```bash npm install -g firebase-tools firebase login dart pub global activate flutterfire_cli ``` -------------------------------- ### Paginated Query Example Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-data-connect/SKILL.md Implement pagination for large datasets by defining queries that accept limit and offset parameters. This example shows a paginated query for listing movies. ```graphql query ListMoviesPaginated($limit: Int!, $offset: Int!) @auth(level: PUBLIC) { movies(limit: $limit, offset: $offset) { id title releaseYear } } ``` -------------------------------- ### Initialize Firebase Storage Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_storage.md Demonstrates how to get an instance of FirebaseStorage, either using the default bucket or specifying a custom bucket URL. ```APIDOC ## Initialize Firebase Storage ### Description Get an instance of FirebaseStorage to interact with Cloud Storage. You can use the default instance or specify a custom bucket. ### Method `FirebaseStorage.instance` or `FirebaseStorage.instanceFor` ### Usage ```dart // Use the default instance final storage = FirebaseStorage.instance; // Explicitly specify the bucket name URL final storage = FirebaseStorage.instanceFor(bucket: "gs://BUCKET_NAME"); ``` ``` -------------------------------- ### Setup and Configuration Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-analytics/SKILL.md Instructions for adding the Firebase Analytics package and initializing it in your Flutter app. Includes details on automatic screen tracking and verification. ```APIDOC ## Setup and Configuration ### Installation ```bash flutter pub add firebase_analytics flutter run ``` ### Initialization ```dart import 'package:firebase_analytics/firebase_analytics.dart'; // After Firebase.initializeApp(): FirebaseAnalytics analytics = FirebaseAnalytics.instance; ``` ### Automatic Screen Tracking For `MaterialApp`: ```dart MaterialApp( navigatorObservers: [ FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance), ], ); ``` For GoRouter: ```dart GoRouter( observers: [FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance)], ); ``` ### iOS Specifics For apps not using IDFA, use `FirebaseAnalyticsWithoutAdIdSupport`: - **Swift Package Manager:** `FIREBASE_ANALYTICS_WITHOUT_ADID=true flutter build ios` - **CocoaPods:** Add `pod 'FirebaseAnalyticsWithoutAdIdSupport', :modular_headers => true` to `Podfile`. ``` -------------------------------- ### Patrol Widget Selector Examples Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/patrol-e2e-testing/SKILL.md Provides examples of various ways to select widgets for interaction within Patrol tests. Covers selection by text, type, icon, and more complex conditions like containing other widgets or specific properties. ```dart $('some text') // by text $(TextField) // by type $(Icons.arrow_back) // by icon ``` ```dart // Tap a widget containing a specific text label await $(Container).$('click').tap(); // Tap a container that contains an ElevatedButton await $(Container).containing(ElevatedButton).tap(); // Tap only the enabled ElevatedButton await $(ElevatedButton) .which( (b) => b.enabled, ) .tap(); ``` ```dart // Enter text into the second TextField on screen await $(TextField).at(1).enterText('your input'); ``` ```dart await $(widget_you_want_to_scroll_to).scrollTo(); ``` ```dart // Grant permission while app is in use await $.native.grantPermissionWhenInUse(); // Open notification shade and tap a notification by text await $.native.openNotifications(); await $.native.tapOnNotificationBySelector( Selector(textContains: 'text'), ); ``` -------------------------------- ### Execute Typed Queries and Mutations Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-data-connect/SKILL.md Use the generated SDK to execute typed queries and mutations. This example shows how to execute a `ListMoviesQuery`, a `CreateMovieMutation`, and a `DeleteMovieMutation`. ```dart // Execute a query final result = await ListMoviesQuery().execute(); final movies = result.data.movies; // Execute a mutation await CreateMovieMutation(title: 'Inception', releaseYear: 2010, genre: 'Sci-Fi') .execute(); // Delete by ID await DeleteMovieMutation(id: movieId).execute(); ``` -------------------------------- ### Dart Doc Comment Example Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/effective-dart/SKILL.md Use `///` doc comments for public APIs. Start with a single-sentence summary, followed by prose explaining parameters, return values, and exceptions. Use `[identifier]` to refer to in-scope identifiers. ```dart /// Returns the sum of [a] and [b]. /// /// Throws [ArgumentError] if either value is negative. int add(int a, int b) { ... } ``` -------------------------------- ### Add Cloud Firestore Package Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-cloud-firestore/SKILL.md Install the Cloud Firestore package for Flutter. ```bash flutter pub add cloud_firestore ``` -------------------------------- ### AuthViewModel Example Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/architecture-feature-first/SKILL.md Demonstrates a ViewModel for authentication, managing loading states, errors, and handling login logic by interacting with an AuthRepository. It uses ChangeNotifier to notify listeners of state changes. ```dart class AuthViewModel extends ChangeNotifier { final AuthRepository _authRepo; AuthViewModel(this._authRepo); bool _isLoading = false; bool get isLoading => _isLoading; String? _error; String? get error => _error; Future login(String email, String password) async { _isLoading = true; _error = null; notifyListeners(); try { await _authRepo.login(email, password); return true; } catch (e) { _error = e.toString(); return false; } finally { _isLoading = false; notifyListeners(); } } } ``` -------------------------------- ### Dart Unit Testing with test package Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/effective-dart/SKILL.md Organize unit tests using `group` and descriptive `test` names. Use `setUp` for common test setup. Assert expected outcomes using `expect` with matchers like `hasLength` and `equals`. ```dart import 'package:test/test'; void main() { group('CartService', () { late CartService cart; setUp(() => cart = CartService()); test('addItem increases item count', () { cart.addItem(Product(id: '1', name: 'Widget', price: 9.99)); expect(cart.items, hasLength(1)); }); test('removeItem decreases total price', () { final product = Product(id: '1', name: 'Widget', price: 9.99); cart.addItem(product); cart.removeItem(product.id); expect(cart.totalPrice, equals(0.0)); }); }); } ``` -------------------------------- ### Monitor Upload Progress Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_storage.md Provides an example of how to monitor the progress of file uploads using upload task streams. ```APIDOC ## Monitor Upload Progress ### Description Track the progress of file uploads to provide real-time feedback to the user. ### Usage ```dart final uploadTask = fileRef.putFile(file); uploadTask.snapshotEvents.listen((TaskSnapshot snapshot) { print('Progress: ${(snapshot.bytesTransferred / snapshot.totalBytes) * 100}%'); }); ``` ``` -------------------------------- ### Feature-First File Structure Example Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/architecture-feature-first/SKILL.md Organizes Flutter code by feature, grouping all layers (data, domain, UI) for a specific feature within a single directory. This promotes modularity and maintainability. ```text lib/ ├── app.dart ├── main.dart ├── core/ # Shared utilities, theme, DI setup │ ├── di/ │ │ └── service_locator.dart │ ├── theme/ │ │ └── app_theme.dart │ └── network/ │ └── api_client.dart ├── features/ │ ├── auth/ │ │ ├── data/ │ │ │ ├── auth_repository.dart │ │ │ └── auth_api_service.dart │ │ ├── domain/ # Optional — only for complex logic │ │ │ └── login_usecase.dart │ │ └── ui/ │ │ ├── auth_viewmodel.dart │ │ ├── login_screen.dart │ │ └── widgets/ │ │ └── login_form.dart │ └── profile/ │ ├── data/ │ │ ├── profile_repository.dart │ │ └── profile_api_service.dart │ └── ui/ │ ├── profile_viewmodel.dart │ └── profile_screen.dart └── shared/ # Shared widgets, models, extensions ├── models/ │ └── user.dart └── widgets/ └── loading_indicator.dart ``` -------------------------------- ### File Operations Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_storage.md Provides examples for creating file references, uploading, downloading, and deleting files in Firebase Storage. ```APIDOC ## File Operations ### Description Perform common file operations such as creating references, uploading, downloading, and deleting files. ### Create File Reference ```dart final storageRef = FirebaseStorage.instance.ref(); final fileRef = storageRef.child("uploads/file.jpg"); ``` ### Upload File ```dart // Assuming 'file' is a File object final uploadTask = fileRef.putFile(file); final snapshot = await uploadTask; final downloadUrl = await snapshot.ref.getDownloadURL(); ``` ### Download File ```dart // Download as bytes final data = await fileRef.getData(); // Get download URL final downloadUrl = await fileRef.getDownloadURL(); ``` ### Delete File ```dart await fileRef.delete(); ``` ``` -------------------------------- ### Google Sign-In for Web Platforms Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_auth.md Utilize Firebase SDK methods for Google Sign-In on web platforms. This example demonstrates adding scopes and custom parameters. ```dart Future signInWithGoogle() async { // Create a new provider GoogleAuthProvider googleProvider = GoogleAuthProvider(); googleProvider.addScope('https://www.googleapis.com/auth/contacts.readonly'); googleProvider.setCustomParameters({ 'login_hint': 'user@example.com' }); // Once signed in, return the UserCredential return await FirebaseAuth.instance.signInWithPopup(googleProvider); } ``` -------------------------------- ### Add Firebase Data Connect Package Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-data-connect/SKILL.md Install the Firebase Data Connect package using Flutter's package manager. ```bash flutter pub add firebase_data_connect ``` -------------------------------- ### Mocking Bloc Methods Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_dart_bloc_mocktail.md Provides an example of mocking other methods on a Bloc, beyond just state emissions. Use `when` to define the behavior of these methods. ```dart when(() => mockCounterCubit.someOtherMethod()).thenReturn('some value'); ``` -------------------------------- ### Log General Event with Parameters Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_analytics.md Log any event, predefined or custom, using the general logEvent method with a name and parameters map. This example logs a 'select_content' event. ```dart await FirebaseAnalytics.instance.logEvent( name: "select_content", parameters: { "content_type": "image", "item_id": itemId, }, ); ``` -------------------------------- ### Define GraphQL Queries and Mutations Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-data-connect/SKILL.md Define GraphQL queries and mutations in a `queries.gql` file. This example includes a public query to list movies and mutations to create and delete movies, with authentication levels specified. ```graphql query ListMovies @auth(level: PUBLIC) { movies { id title releaseYear genre rating } } mutation CreateMovie($title: String!, $releaseYear: Int, $genre: String) @auth(level: USER) { movie_insert(data: { title: $title releaseYear: $releaseYear genre: $genre }) } mutation DeleteMovie($id: UUID!) @auth(level: USER) { movie_delete(id: $id) } ``` -------------------------------- ### Initialize Firebase Analytics Instance Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-analytics/SKILL.md Import the Firebase Analytics library and get an instance of FirebaseAnalytics after initializing Firebase. ```dart import 'package:firebase_analytics/firebase_analytics.dart'; // After Firebase.initializeApp(): FirebaseAnalytics analytics = FirebaseAnalytics.instance; ``` -------------------------------- ### Upload File and Get Download URL Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_storage.md Upload a file to Cloud Storage using `putFile()` and retrieve its download URL upon successful upload. ```dart final uploadTask = fileRef.putFile(file); final snapshot = await uploadTask; final downloadUrl = await snapshot.ref.getDownloadURL(); ``` -------------------------------- ### Setup Riverpod with ProviderScope Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/riverpod/SKILL.md Wrap your application with ProviderScope at the root level, typically within the main function. Ensure ProviderScope is not nested inside your main app widget. ```dart void main() { runApp(const ProviderScope(child: MyApp())); } ``` -------------------------------- ### Query Documents with Filters and Ordering Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-cloud-firestore/SKILL.md Query documents in a collection based on specified filters and order. This example filters by age, orders by age, and limits the results. ```dart final query = db.collection("users") .where("age", isGreaterThanOrEqualTo: 18) .orderBy("age") .limit(20); final results = await query.get(); ``` -------------------------------- ### Define GraphQL Schema for Data Connect Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-data-connect/SKILL.md Define your data model using GraphQL schema definition language in a `schema.gql` file. This example defines a 'Movie' type with various fields. ```graphql type Movie @table { id: UUID! @default(expr: "uuidV4()") title: String! releaseYear: Int genre: String rating: Float description: String } ``` -------------------------------- ### Flutter Widget Test Example Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/testing/SKILL.md Tests UI components by simulating user interactions and state changes. Wrap widgets in `MaterialApp` and use `pump()` or `pumpAndSettle()` for frame rendering. ```dart testWidgets('should display error message on failure', (tester) async { await tester.pumpWidget( MaterialApp( home: BlocProvider.value( value: mockLoginCubit, child: const LoginView(), ), ), ); // Simulate failure state whenListen( mockLoginCubit, Stream.fromIterable([const LoginState(status: LoginStatus.failure, errorMessage: 'Invalid')]), initialState: const LoginState(), ); await tester.pump(); expect(find.text('Invalid'), findsOneWidget); }); ``` -------------------------------- ### Basic Patrol Test Structure Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/patrol-e2e-testing/SKILL.md Demonstrates the fundamental structure of a Patrol test, including setup, widget interaction, and assertion. Use `patrolTest` instead of `testWidgets`, and find widgets using keys with `$`. Ensure explicit wait conditions are used. ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:patrol/patrol.dart'; void main() { patrolTest( 'user can log in successfully', ($) async { await $.pumpWidgetAndSettle(const MyApp()); const email = String.fromEnvironment('E2E_EMAIL'); const password = String.fromEnvironment('E2E_PASSWORD'); await $(#emailField).enterText(email); await $(#passwordField).enterText(password); await $(#loginButton).tap(); await $.waitUntilVisible($(#homeScreenTitle)); expect($(#homeScreenTitle).text, equals('Welcome')); }, ); } ``` -------------------------------- ### Dart Mocking with Mocktail Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/testing/SKILL.md Sets up mock objects using the `mocktail` package. Use `setUpAll` to register fallback values for custom types passed to `any()`. Mock at the repository boundary. ```dart class MockAuthRepository extends Mock implements AuthRepository {} void main() { setUpAll(() { registerFallbackValue(FakeLoginRequest()); }); // ... tests } ``` -------------------------------- ### Firestore Security Rules Example Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-cloud-firestore/SKILL.md Example Firebase Security Rules for user-owned documents. These rules define read, update, delete, and create permissions based on user authentication and ownership. ```firestore_rules rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read, update, delete: if request.auth != null && request.auth.uid == userId; allow create: if request.auth != null; } } } ``` -------------------------------- ### Firebase Realtime Database Security Rules Example Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_database.md Example of Firebase Realtime Database security rules. These rules define read and write access for user data, ensuring only authenticated users can access their own information. ```json { "rules": { "users": { "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } } } } ``` -------------------------------- ### Clone All Skills via CLI Source: https://github.com/evanca/flutter-ai-rules/blob/main/README.md Use this command to download all available skills into a local .skills folder within your project. This allows for easy referencing of individual skills in prompts or IDE configurations. ```sh git clone --depth 1 https://github.com/evanca/flutter-ai-rules.git temp_repo && mkdir -p .skills && cp -r temp_repo/skills/* .skills && rm -rf temp_repo ``` -------------------------------- ### Running Patrol Tests via CLI Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/patrol-e2e-testing/SKILL.md Illustrates different command-line interface commands for executing Patrol tests. Includes options for running all tests, developing with live reload, targeting specific files, running on web, and filtering by tags. ```bash patrol test ``` ```bash patrol develop -t integration_test/my_test.dart ``` ```bash patrol test --target patrol_test/login_test.dart ``` ```bash patrol test --device chrome ``` ```bash patrol test --device chrome --web-headless true ``` ```bash patrol test --tags android ``` -------------------------------- ### Get File Metadata Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_storage.md Retrieve metadata associated with a file, such as content type and size. ```dart final metadata = await fileRef.getMetadata(); print('Content type: ${metadata.contentType}'); print('Size: ${metadata.size}'); ``` -------------------------------- ### Create File References Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_storage.md Create a reference to a file in your Cloud Storage bucket using the root reference and child paths. ```dart final storageRef = FirebaseStorage.instance.ref(); final fileRef = storageRef.child("uploads/file.jpg"); ``` -------------------------------- ### Add Firebase Analytics Dependency Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-analytics/SKILL.md Add the Firebase Analytics package to your Flutter project and run the app to install it. ```bash flutter pub add firebase_analytics flutter run ``` -------------------------------- ### Create User with Email and Password Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_auth.md Register a new user account using an email address and password. Handles potential errors like weak passwords or existing accounts. ```dart try { final credential = await FirebaseAuth.instance.createUserWithEmailAndPassword( email: emailAddress, password: password, ); } on FirebaseAuthException catch (e) { if (e.code == 'weak-password') { print('The password provided is too weak.'); } else if (e.code == 'email-already-in-use') { print('The account already exists for that email.'); } } catch (e) { print(e); } ``` -------------------------------- ### Testing Bloc with BlocProvider Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_dart_bloc_mocktail.md Demonstrates how to provide a mocked Bloc to your widget tree using `BlocProvider` for testing purposes. This is crucial for widget testing. ```dart await tester.pumpWidget( BlocProvider.value( value: mockCounterCubit, child: MyWidget(), ), ); // Stub the initial state before the first pump when(() => mockCounterCubit.state).thenReturn(CounterState.initial()); await tester.pump(); ``` -------------------------------- ### Automate FlutterFire Configuration for Multiple Flavors Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/flutterfire_configure.md A bash script to automate the FlutterFire configuration process for different flavors. It takes the flavor name as an argument and dynamically sets project IDs, output paths, and package names. ```bash #!/bin/bash # Check if a flavor argument is provided if [ -z "$1" ]; then echo "Usage: $0 " echo "Example: $0 dev" exit 1 fi FLAVOR=$1 PROJECT_ID="flutter-app-$FLAVOR" # Run FlutterFire CLI with the appropriate arguments flutterfire config \ --project=$PROJECT_ID \ --out=lib/firebase_options_$FLAVOR.dart \ --ios-bundle-id=com.example.flutterApp.$FLAVOR \ --ios-out=ios/flavors/$FLAVOR/GoogleService-Info.plist \ --android-package-name=com.example.flutter_app.$FLAVOR \ --android-out=android/app/src/$FLAVOR/google-services.json ``` -------------------------------- ### Get Initial Message Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_messaging.md Retrieves the initial message that launched the application from a terminated state. This `RemoteMessage` is consumed once retrieved. ```APIDOC ## Get Initial Message ### Description Retrieves the initial message that launched the application from a terminated state. This `RemoteMessage` is consumed once retrieved. ### Method `FirebaseMessaging.instance.getInitialMessage()` ### Return Value - `Future`: A future that resolves to a `RemoteMessage` if the app was opened from a notification, otherwise null. ### Request Example ```dart RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); if (initialMessage != null) { // App opened from terminated state via notification } ``` ``` -------------------------------- ### Initialize Firebase with Emulator Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-auth/SKILL.md Initialize Firebase and configure it to use the local emulator for testing authentication features. ```dart Future main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); await FirebaseAuth.instance.useAuthEmulator('localhost', 9099); // ... } ``` -------------------------------- ### Get File Download URL Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_storage.md Retrieve the publicly accessible download URL for a file stored in Cloud Storage. ```dart final downloadUrl = await fileRef.getDownloadURL(); ``` -------------------------------- ### Mocking a Bloc with Mocktail Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_dart_bloc_mocktail.md Demonstrates how to create a mock instance of a Bloc using Mocktail. This is essential for isolating the Bloc during testing. ```dart import 'package:bloc/bloc.dart'; import 'package:mocktail/mocktail.dart'; class MockCounterCubit extends Mock implements CounterCubit {} // In your test: final mockCounterCubit = MockCounterCubit(); ``` -------------------------------- ### Log Custom Event Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_analytics.md Log a custom event with a descriptive name and relevant parameters. This example logs a 'share_image' event. ```dart await FirebaseAnalytics.instance.logEvent( name: "share_image", parameters: { "image_name": name, "full_text": text, }, ); ``` -------------------------------- ### Initialize Firebase Database Reference Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-database/SKILL.md Import the Firebase database library and obtain a reference to the database after initializing Firebase. ```dart import 'package:firebase_database/firebase_database.dart'; // After Firebase.initializeApp(): final DatabaseReference ref = FirebaseDatabase.instance.ref(); ``` -------------------------------- ### Add Firebase App Check Dependency Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-app-check/SKILL.md Install the Firebase App Check SDK for Flutter using the Flutter package manager. ```bash flutter pub add firebase_app_check ``` -------------------------------- ### Parameters and Properties Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-analytics/SKILL.md Details on setting default event parameters and constraints for parameter names and values. ```APIDOC ## Parameters and Properties ### Setting Default Parameters Set default parameters for all future events (not supported on web): ```dart await FirebaseAnalytics.instance.setDefaultEventParameters({ 'app_version': '1.2.3', 'environment': 'production', }); ``` Clear a default parameter by setting it to `null`. ``` -------------------------------- ### Combining Providers with select Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_with_riverpod.md Shows how to selectively listen to specific parts of a provider's state using `select`. This optimizes widget rebuilds. ```dart final complexProvider = Provider((ref) => { 'name': 'Example', 'value': 100 }); class MyWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // Only rebuilds when the 'value' changes final value = ref.watch(complexProvider.select((data) => data['value'])); return Text('Value: $value'); } } ``` -------------------------------- ### Create Mock Instance Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/mockito.md Create instances of your generated mock classes. This is typically done after running the build runner to generate the mock files. ```dart var mock = MockCat(); ``` -------------------------------- ### Declare a Simple Provider with @riverpod Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_with_riverpod__under_6K.md Use the @riverpod annotation for automatic code generation of providers. This example declares a simple integer provider. ```dart @riverpod int example(ref) { return 0; } ``` -------------------------------- ### Use Pod for iOS SDK Frameworks Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/cloud_firestore.md For iOS & macOS, consider using pre-compiled frameworks to improve build times by modifying your Podfile. Replace IOS_SDK_VERSION with the actual SDK version. ```ruby pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => 'IOS_SDK_VERSION' ``` -------------------------------- ### Get FCM Token with VAPID Key (Web) Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_messaging.md For web platforms, provide your VAPID public key when requesting a token using `getToken()`. ```dart final fcmToken = await FirebaseMessaging.instance.getToken( vapidKey: "BKagOny0KF_2pCJQ3m....moL0ewzQ8rZu" ); ``` -------------------------------- ### Basic Provider Usage in Flutter Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_with_riverpod.md Demonstrates how to create and consume a simple provider using Riverpod. Ensure the provider is accessible within the widget tree. ```dart final countProvider = Provider((ref) => 0); class MyWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final count = ref.watch(countProvider); return Text('$count'); } } ``` -------------------------------- ### Read Data Once with get() Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_database.md Use asynchronous calls to read data once. This method retrieves data from the database and is suitable for one-time data fetches. ```dart final snapshot = await FirebaseDatabase.instance.ref('users/123').get(); if (snapshot.exists) { print(snapshot.value); } ``` -------------------------------- ### Google Sign-In for Web Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-auth/SKILL.md Implement Google Sign-In for web applications. This method uses `signInWithPopup` and allows customization with scopes and login hints. ```dart Future signInWithGoogle() async { GoogleAuthProvider googleProvider = GoogleAuthProvider(); googleProvider.addScope('https://www.googleapis.com/auth/contacts.readonly'); googleProvider.setCustomParameters({'login_hint': 'user@example.com'}); return await FirebaseAuth.instance.signInWithPopup(googleProvider); } ``` -------------------------------- ### Using Argument Matchers Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_dart_riverpod_mockito.md Employ argument matchers like `any`, `argThat`, `captureAny`, and `captureThat` for flexible stubbing and verification. Avoid using `null` directly next to an argument matcher. ```dart import 'package:mockito/mockito.dart'; // Assuming mock is an instance of a generated mock class // when(mock.method(any, namedArg: any)); // verify(mock.method(argThat(equals(expectedValue)))); // captureAny(mock.method()); // captureThat(mock.method(), (value) => print(value)); ``` -------------------------------- ### Get FCM Registration Token in Flutter Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-messaging/SKILL.md Retrieve the FCM registration token for the current device. This token is used to send messages to a specific device. ```dart final fcmToken = await FirebaseMessaging.instance.getToken(); ``` -------------------------------- ### Centralized Firebase Initialization for Flavors Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/flutterfire-configure/SKILL.md Centralize Firebase initialization logic to select the correct configuration based on the app flavor at runtime. Import flavor-specific options using namespace aliases. ```dart // firebase.dart import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/services.dart'; import 'package:flutter_app/firebase_options_prod.dart' as prod; import 'package:flutter_app/firebase_options_stg.dart' as stg; import 'package:flutter_app/firebase_options_dev.dart' as dev; Future initializeFirebaseApp() async { final firebaseOptions = switch (appFlavor) { 'prod' => prod.DefaultFirebaseOptions.currentPlatform, 'stg' => stg.DefaultFirebaseOptions.currentPlatform, 'dev' => dev.DefaultFirebaseOptions.currentPlatform, _ => throw UnsupportedError('Invalid flavor: $appFlavor'), }; await Firebase.initializeApp(options: firebaseOptions); } ``` ```dart // main.dart void main() async { WidgetsFlutterBinding.ensureInitialized(); await initializeFirebaseApp(); runApp(const MainApp()); } ``` -------------------------------- ### Order by Child Value Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_database.md Query data in Firebase Realtime Database and order the results by a specific child's value. This example orders 'dinosaurs' by their 'height'. ```dart // Order results by child value final ref = FirebaseDatabase.instance.ref("dinosaurs"); final query = ref.orderByChild("height"); ``` -------------------------------- ### Defer setState During Build with addPostFrameCallback Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/flutter-errors/SKILL.md Safely call setState or showDialog after the build method has completed by using addPostFrameCallback. This is useful for initial setup or data loading. ```dart @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { // Safe to call setState or showDialog here }); } ``` -------------------------------- ### Using BLoC in Flutter Widgets Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_with_bloc.md Demonstrates how to integrate a BLoC with Flutter widgets to display state and dispatch events. Requires the `flutter_bloc` package. ```dart import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; // Assuming CounterBloc, CounterState, IncrementEvent, DecrementEvent are defined as above void main() { runApp( MaterialApp( home: BlocProvider( create: (context) => CounterBloc(), child: CounterPage(), ), ), ); } class CounterPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Counter App')) body: Center( child: BlocBuilder( builder: (context, state) { if (state is CounterInitial) { return Text('Initial State'); } else if (state is CounterValue) { return Text('Value: ${state.value}'); } return Container(); // Should not happen }, ), ), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ FloatingActionButton( onPressed: () => context.read().add(IncrementEvent()), tooltip: 'Increment', child: Icon(Icons.add), ), SizedBox(height: 8), FloatingActionButton( onPressed: () => context.read().add(DecrementEvent()), tooltip: 'Decrement', child: Icon(Icons.remove), ), ], ), ); } } ``` -------------------------------- ### Initialize Firebase Remote Config Instance Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-remote-config/SKILL.md Import the Firebase Remote Config package and get an instance of FirebaseRemoteConfig. This is the entry point for all Remote Config operations. ```dart import 'package:firebase_remote_config/firebase_remote_config.dart'; final remoteConfig = FirebaseRemoteConfig.instance; ``` -------------------------------- ### Setting up Multiple Providers with MultiProvider Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/provider/SKILL.md Use MultiProvider to group multiple providers and avoid deeply nested trees. ChangeNotifierProvider automatically disposes of the model when it's no longer needed. Never create a provider's object from variables that can change over time; use ProxyProvider instead. If you have 150+ providers, consider mounting them over time to avoid StackOverflowError. ```dart MultiProvider( providers: [ Provider(create: (_) => Something()), ChangeNotifierProvider(create: (_) => MyNotifier()), FutureProvider(create: (_) => fetchData(), initialData: ''), ], child: MyApp(), ) ``` -------------------------------- ### Set up and Cancel Real-time Listener in Dart Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/cloud_firestore.md Demonstrates how to set up a real-time listener for Firestore snapshots and how to cancel it when it's no longer needed. Ensure listeners are detached to free up resources. ```dart final subscription = db.collection("users") .snapshots() .listen((event) { // Handle the data }); // Later, when no longer needed: subscription.cancel(); ``` -------------------------------- ### Get APNS Token Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_messaging.md Retrieves the Apple Push Notification Service (APNS) token. This is required for making FCM plugin API calls on Apple platforms. ```APIDOC ## Get APNS Token ### Description Retrieves the Apple Push Notification Service (APNS) token. This is required for making FCM plugin API calls on Apple platforms. ### Method `FirebaseMessaging.instance.getAPNSToken()` ### Request Example ```dart final apnsToken = await FirebaseMessaging.instance.getAPNSToken(); if (apnsToken != null) { // APNS token is available, make FCM plugin API requests } ``` ``` -------------------------------- ### Add Firebase Crashlytics and Analytics Dependencies Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-crashlytics/SKILL.md Install the necessary packages for Firebase Crashlytics and Firebase Analytics. Analytics enables breadcrumb logs for better crash context. ```bash flutter pub add firebase_crashlytics flutter pub add firebase_analytics # enables breadcrumb logs for better crash context ``` -------------------------------- ### Flattened Data Structure Example Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-database/SKILL.md Illustrates a flattened data structure pattern for Firebase Realtime Database, separating related data into top-level paths to optimize reads. ```dart // Instead of nesting chat messages inside rooms: // rooms/roomId/messages/messageId/... // Flatten into separate top-level paths: // rooms/roomId: { name: "General", createdBy: "uid1" } // room-members/roomId: { uid1: true, uid2: true } // room-messages/roomId/messageId: { text: "Hello", sender: "uid1", timestamp: ... } ``` -------------------------------- ### Dart Records: Creation, Typing, and Access Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/dart-3-updates/SKILL.md Demonstrates how to create, annotate types for, and access fields of records in Dart. Records are anonymous, immutable, fixed-size aggregates. ```dart var record = ('first', a: 2, b: true, 'last'); // Type annotation ({int a, bool b}) namedRecord; // Access print(record.$1); // positional: 'first' print(record.a); // named: 2 ``` -------------------------------- ### Main Application Entry Point with Firebase Initialization Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/flutterfire_configure.md The main entry point for a Flutter application that ensures Firebase is initialized before the app runs. It calls the `initializeFirebaseApp` function to set up the correct Firebase configuration based on the app's flavor. ```dart // main.dart import 'firebase.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await initializeFirebaseApp(); runApp(const MainApp()); } ``` -------------------------------- ### Event Logging Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/firebase-analytics/SKILL.md Demonstrates how to log predefined and custom analytics events using `logSelectContent` and `logEvent`. ```APIDOC ## Event Logging ### Logging Predefined Events Use predefined event methods when possible: ```dart await FirebaseAnalytics.instance.logSelectContent( contentType: "image", itemId: itemId, ); ``` ### Logging Custom Events Use the general `logEvent()` method for both predefined and custom events: ```dart await FirebaseAnalytics.instance.logEvent( name: "select_content", parameters: { "content_type": "image", "item_id": itemId, }, ); ``` ### Custom Event Example — E-commerce Add-to-Cart ```dart Future logAddToCart(String productId, String productName, double price) async { await FirebaseAnalytics.instance.logEvent( name: 'add_to_cart', parameters: { 'product_id': productId, 'product_name': productName, 'price': price, 'currency': 'USD', }, ); } ``` ``` -------------------------------- ### Consume CartModel state deeply nested Source: https://github.com/evanca/flutter-ai-rules/blob/main/skills/flutter-change-notifier/SKILL.md Place Consumer widgets as deep in the widget tree as possible to minimize the scope of rebuilds. This example shows a deeply nested Consumer. ```dart HumongousWidget( child: AnotherMonstrousWidget( child: Consumer( builder: (context, cart, child) { return Text('Total price: ${cart.totalPrice}'); }, ), ), ) ``` -------------------------------- ### Dependency Injection with Provider Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_with_riverpod.md Illustrates how Riverpod facilitates dependency injection. Providers can depend on other providers. ```dart final dependencyProvider = Provider((ref) => 'Dependency Data'); final dependentProvider = Provider((ref) { final dependency = ref.watch(dependencyProvider); return 'Dependent on $dependency'; }); class MyWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final data = ref.watch(dependentProvider); return Text(data); } } ``` -------------------------------- ### Perform Atomic Updates with runTransaction() Source: https://github.com/evanca/flutter-ai-rules/blob/main/rules/firebase/firebase_database.md Use transactions for operations that require atomic updates, ensuring data consistency even with concurrent modifications. This example increments a like count. ```dart FirebaseDatabase.instance.ref('posts/123/likes').runTransaction((currentValue) { return (currentValue as int? ?? 0) + 1; }); ``` -------------------------------- ### Mocking a Provider with Mockito Source: https://github.com/evanca/flutter-ai-rules/blob/main/combined/flutter_dart_riverpod_mockito.md Demonstrates how to create a mock object for a Riverpod provider using Mockito. This is essential for testing components that depend on this provider without executing the actual provider logic. ```dart import 'package:mockito/mockito.dart'; import 'package:riverpod/riverpod.dart'; // Assume MyService is a class you want to mock class MyService { String getData() => 'real data'; } // Assume myServiceProvider is a Riverpod provider that exposes MyService final myServiceProvider = Provider((ref) => MyService()); // Define a Mock class for MyService class MockMyService extends Mock implements MyService {} // Define a Mock class for the Provider class MockMyServiceProvider extends Mock implements Provider {} void main() { // Example usage in a test (conceptual) // final mockService = MockMyService(); // final mockProvider = MockMyServiceProvider(); // when(mockProvider.create(any)).thenReturn(mockService); // when(mockService.getData()).thenReturn('mocked data'); // Now you can use mockProvider in your tests where myServiceProvider is expected. } ```