Sharing Knowledge with
the Community
What we learn while building products - shared
with the developer & startup community.

FlutterFlow’s New Feature: App Events (A Game Changer for Scalable Apps)
Building scalable applications in low-code platforms has always been a balance between speed and maintainability. While FlutterFlow makes UI development incredibly fast, managing communication between different parts of an app could sometimes become complex. But with the introduction of App Events, FlutterFlow has taken a major step forward — bringing cleaner architecture, better performance, and a much more scalable approach to app development. The Problem Before App Events Before this update, handling communication between screens or components often involved: Passing multiple navigation parameters Managing complex global or local state Writing tightly coupled logic between screens As apps grew larger, this approach became: Hard to maintain Difficult to debug Less scalable What Are App Events? App Events introduce a decoupled communication system inside FlutterFlow. Core Idea: Trigger an event from anywhere in the app Listen and respond to that event from anywhere No direct connection between components is required. This means your app becomes: More modular Easier to maintain Much cleaner in terms of logic How It Works (Simple Example) Let’s say a user adds an item to the cart 🛒 Without App Events: Manually update cart badge Refresh product list Update summary screen Pass state across multiple screens With App Events: Trigger event → “Cart Updated” All relevant UI components automatically react That’s it. No messy logic. Key Highlights Global Events App-level events Handled across the entire application Processed sequentially Perfect for: Authentication state changes Analytics tracking Logging Local Events Scoped to specific pages or components Support multiple listeners Trigger instant UI updates Perfect for: UI refresh Component communication Dynamic interactions Why This Feature Matters App Events bring FlutterFlow closer to modern software architecture patterns, such as: Event-driven systems Loose coupling Reactive UI updates Benefits: Less complex code structure Better performance Easier debugging Improved scalability My Take This is easily one of the most impactful updates in FlutterFlow in recent times. It solves a real problem developers face when scaling apps and introduces a pattern that aligns with how modern applications are built. Final Thoughts FlutterFlow continues to evolve beyond just a UI builder — it’s becoming a serious development platform capable of handling complex applications. App Events are a big step in that direction. If you haven’t explored it yet, now is the time. #FlutterFlow #NoCode #LowCode #AppDevelopment #MobileDevelopment #Firebase #UIUX #TechUpdate #Developers

Integrating Tamara Payment Gateway in a FlutterFlow Application
In today’s digital ecosystem, integrating a reliable payment gateway is essential for delivering a smooth and secure user experience. However, building a payment system isn’t just about processing transactions — it’s about ensuring security, reliability, and compliance, all while maintaining a seamless user journey. Recently, I worked on integrating the Tamara Payment Gateway into a FlutterFlow application, creating a complete end-to-end payment workflow — from initiating transactions to handling real-time updates. The Goal The objective was to implement a secure and scalable payment flow that: Enables users to complete payments smoothly Handles transaction states reliably Ensures compliance with Tamara’s payment standards Works seamlessly across development and production environments The Implementation The integration involved connecting Tamara’s APIs with the FlutterFlow application and managing the full payment lifecycle. Key Features Implemented Tamara Checkout API Integration We used Tamara’s Checkout API to: Initiate payment sessions Redirect users to the hosted checkout page Process transactions securely Secure Payment Handling Security was a top priority. The implementation ensured: Proper API request validation Safe handling of transaction data Compliance with Tamara’s payment flow Webhook Integration for Real-Time Updates To keep track of payment status: Implemented webhooks to receive real-time updates Handled events such as: Payment success Payment failure Transaction updates This ensures the app always reflects the correct payment status. Payment Method Support Enabled support for: Visa cards Mada cards This ensures compatibility with regional payment preferences. Environment Configuration Set up both environments: Sandbox (Development) for testing Production for live transactions This separation ensures safe development and smooth deployment. Reliable Request & Response Handling Carefully managed API communication to: Handle success and failure cases Prevent duplicate transactions Ensure consistency across the payment flow Key Challenge: Hosted Checkout Limitations One of the most interesting aspects of this integration was understanding the limitations of Tamara’s hosted checkout flow. Unlike custom UI payment solutions: The payment interface is controlled by Tamara UI customization options are limited Why This Matters At first, this might seem like a limitation, but it actually ensures: Higher security standards Compliance with payment regulations Reduced risk of implementation errors Understanding these constraints helped align the integration with best practices recommended by Tamara. Final Result The final implementation delivered: A stable and secure payment experience Smooth transaction processing Accurate real-time payment updates Full compliance with Tamara’s standards Users can now complete payments confidently, knowing the system is both secure and reliable. Key Learnings Balancing UX and Security Not all payment flows allow full UI control. Sometimes, prioritizing security and compliance is more important than customization. Importance of Webhooks Webhooks are critical for: Real-time updates Backend synchronization Reliable transaction tracking Tech Stack FlutterFlow Dart Tamara Payment Gateway APIs Webhooks for real-time updates Final Thoughts This integration reinforced an important lesson: A great payment system is not just about UX — it’s about trust, security, and reliability. By combining FlutterFlow with Tamara’s infrastructure, we were able to build a solution that meets both user expectations and industry standards. If you’re working on payment integrations, always remember: Understand platform limitations Follow recommended flows Prioritize security over customization #FlutterFlow #PaymentGateway #Tamara #Fintech #MobileDevelopment #APIIntegration #Webhooks

1. How I Built a Production-Ready AI Chat App in FlutterFlow (With OpenAI + Firebase)
Introduction AI is everywhere in 2026 — but building a production-ready AI chat app is still challenging, especially when using low-code tools like FlutterFlow. In this article, I’ll walk you through how I built a scalable AI chat system using FlutterFlow + Firebase + OpenAI API. Architecture Overview My setup looks like this: Frontend → FlutterFlow UI Backend → Firebase (Firestore + Cloud Functions) AI Engine → OpenAI API Storage → Chat history in Firestore Chat Data Structure Each message is stored like this: { "userId": "123", "message": "Hello AI", "response": "Hi, how can I help?", "timestamp": "server_time" } This allows: Easy chat history retrieval Real-time UI updates Scalable structure Securing OpenAI API Never expose your API key in the frontend. Instead: Use Firebase Cloud Functions Send request → backend → OpenAI → return response This keeps your app secure. Handling Token Usage (Cost Control) AI APIs can get expensive. What I did: Limit message length Store token usage Restrict free users (daily limit) UI Challenges & Solutions Problem: Chat UI lag with many messages Solution: Pagination Lazy loading Efficient Firestore queries Final Result Real-time AI chat Scalable backend Controlled cost Smooth UI Final Thoughts FlutterFlow is powerful — but combining it with backend logic is the real game-changer.

FlutterFlow + RevenueCat: Complete Guide to Subscription Apps
Introduction If you’re building a SaaS or premium mobile app, subscriptions are one of the most reliable monetization models. But implementing subscriptions correctly is not just about adding a payment button — it involves: Secure validation Real-time status updates Handling edge cases (expiry, restore, refunds) In this guide, I’ll walk you through how I implemented a production-ready subscription system using FlutterFlow + RevenueCat + Firebase. Why RevenueCat? Instead of directly handling App Store / Play Store billing, I used RevenueCat because it simplifies everything. Key Benefits: Single integration for both iOS & Android Handles receipts, validation, and renewals Real-time subscription status via webhooks Reduces development complexity Without RevenueCat, managing subscriptions manually becomes very complex. System Architecture (Simple View) Here’s how the system works: FlutterFlow App (Frontend) User interacts with UI (Upgrade, Restore) RevenueCat SDK Handles purchase flow RevenueCat Server Validates transactions Firebase (Firestore + Cloud Functions) Stores subscription status & triggers updates Complete Subscription Flow Here’s the exact flow I implemented: 1. User Action User clicks “Upgrade to Premium” 2. Purchase Trigger RevenueCat SDK opens native purchase screen (App Store / Play Store) 3. Payment Processing Payment handled securely by Apple/Google RevenueCat validates purchase 4. Webhook Trigger RevenueCat sends event → Firebase Cloud Function 5. Firestore Update User document is updated: { "isPremium": true, "plan": "monthly", "expiryDate": "timestamp" } 6. UI Update FlutterFlow listens to Firestore Premium features unlock instantly Firestore Database Structure To keep things scalable and clean, I used this structure: users collection { "userId": "123", "isPremium": true, "plan": "yearly", "expiryDate": "timestamp" } subscriptions collection { "planId": "monthly_001", "price": 9.99, "duration": "1 month" } events collection (VERY IMPORTANT) { "userId": "123", "eventType": "PURCHASE", "timestamp": "server_time" } This helps in: Tracking revenue Debugging issues Analytics Handling Edge Cases (Most Developers Miss This) This is where most apps fail 1. Expired Subscription Check expiryDate regularly Disable premium access automatically 2. Restore Purchases Add Restore button Sync with RevenueCat Update Firestore again 3. Cancelled Subscription User cancels from App Store RevenueCat webhook updates backend Access removed after expiry 4. Refunds RevenueCat sends refund event Immediately update user access Backend Validation (CRITICAL) Never trust frontend logic Always validate subscription from backend using: Why? Prevents fake unlock hacks Ensures real subscription status Keeps your app secure Performance & Cost Optimization Here’s what I optimized: Avoid Excessive Reads Store only required subscription fields Don’t fetch full history every time Use Real-Time Listeners Smartly Listen only to user document Avoid unnecessary listeners Cache Subscription Status Reduce repeated API calls UI Best Practices (Conversion Focused) Subscription UI is not just design — it impacts revenue 💰 What worked for me: Highlight best plan (yearly) Show discount badge (Save 30%) Clear CTA: “Upgrade Now” Add trust elements (secure payment, cancel anytime) Final Result After implementing this system: Smooth and secure purchase flow Real-time subscription updates Scalable backend architecture Reduced bugs and edge case failures Final Thoughts FlutterFlow + RevenueCat is a powerful combination for building subscription-based apps quickly. But the real difference comes from: Proper backend validation Clean database design Handling real-world edge cases That’s what turns a basic app into a production-ready SaaS product.

How to Create and Use RPC Functions in Supabase with Flutter (Step-by-Step Guide)
Introduction When building modern apps, you often need to perform complex database operations — like filtering data, calculating values, or combining multiple queries. Writing all this logic directly in your Flutter app can quickly become messy and inefficient. That’s where RPC (Remote Procedure Call) functions in Supabase come in. RPC functions allow you to write SQL functions inside your database and call them directly from your app as if they were APIs. Why use RPC functions in Supabase? Keep business logic inside the database (cleaner architecture) Reduce network calls (better performance) Improve security (controlled access to data) Reuse logic across multiple clients (Flutter, Web, etc.) Prerequisites Before we start, make sure you have: A Flutter project set up A Supabase project created Supabase Flutter SDK installed Basic knowledge of SQL (SELECT, WHERE, etc.) Step 1: Create an RPC Function in Supabase Let’s say we have a tasks table and we want to fetch all completed tasks for a specific user. Example Table: tasks idtitleuser_idis_completed1Task A101true2Task B101false SQL Function Go to Supabase Dashboard → SQL Editor, and run: create or replace function get_completed_tasks(p_user_id uuid) returns table ( id uuid, title text, is_completed boolean ) language sql as $$ select id, title, is_completed from tasks where user_id = p_user_id and is_completed = true; $$; Explanation (Simple) create or replace function → creates the RPC function p_user_id → input parameter returns table → defines output structure select ... → actual query logic Step 2: Test the Function in Supabase Before using it in Flutter, test it. Run this in SQL Editor: select * from get_completed_tasks('your-user-id-here'); Expected Output You should see only completed tasks for that user. Step 3: Call RPC Function in Flutter Now let’s call this function from your Flutter app. Add Supabase Dependency dependencies: supabase_flutter: latest_version Initialize Supabase await Supabase.initialize( url: 'YOUR_SUPABASE_URL', anonKey: 'YOUR_SUPABASE_ANON_KEY', ); Call RPC Function final supabase = Supabase.instance.client; Future getCompletedTasks(String userId) async { final response = await supabase.rpc( 'get_completed_tasks', params: {'p_user_id': userId}, ); return response; } Explanation rpc() → calls Supabase function 'get_completed_tasks' → function name params → must match SQL parameter names Use in UI FutureBuilder( future: getCompletedTasks(userId), builder: (context, snapshot) { if (!snapshot.hasData) { return CircularProgressIndicator(); } final tasks = snapshot.data as List; return ListView.builder( itemCount: tasks.length, itemBuilder: (context, index) { final task = tasks[index]; return ListTile( title: Text(task['title']), subtitle: Text("Completed"), ); }, ); }, ); Real-World Use Case Let’s say you’re building a Task Management App (like your current Flutter project 👀). Instead of: Fetching all tasks Filtering in Flutter You can: Use RPC to fetch only required data Improve performance and reduce app logic Other Use Cases Calculating total revenue Fetching user-specific dashboards Complex joins across tables Role-based data filtering Common Mistakes 1. Parameter Name Mismatch params: {'userId': userId} // WRONG Must match SQL: p_user_id 2. Forgetting Permissions (RLS) If Row Level Security (RLS) is enabled: Make sure policies allow access 3. Returning Wrong Data Type If your function returns: returns json Then handle it properly in Flutter. 4. Not Testing in SQL First Always test in Supabase before calling from Flutter. Best Practices Keep functions simple and focused One function = one responsibility Use meaningful names get_user_tasks ✔ fetch_data ❌ Secure with RLS policies Don’t expose sensitive data Use indexes for performance Especially for large datasets Prefer SQL functions over multiple API calls Cleaner + faster Conclusion RPC functions in Supabase are a powerful way to move logic closer to your database, making your Flutter apps: Faster Cleaner More secure By following this step-by-step guide, you can now: Create SQL functions Test them in Supabase Call them seamlessly from Flutter Next Steps Add pagination to your RPC functions Use PostgreSQL joins inside functions Explore Edge Functions vs RPC Build reusable backend logic library If you’re building scalable Flutter apps with Supabase, mastering RPC is a game changer

Flutter Performance Optimization: 10 Proven Tips to Make Your App Faster
Flutter makes it incredibly easy to build beautiful cross-platform apps. But as your app grows, performance can quickly become a bottleneck — laggy UI, dropped frames, slow builds… and frustrated users. In today’s competitive app ecosystem, performance is not optional. Users expect smooth animations, fast load times, and responsive interactions. Even a delay of a few milliseconds can impact user retention. In this guide, we’ll explore 10 practical and proven tips to optimize your Flutter app performance — with clear explanations and code examples where needed. 1. Minimize Unnecessary Widget Rebuilds Why it matters: Frequent widget rebuilds can slow down your app and cause UI lag. Best Practices Use const widgets wherever possible Use efficient builders like: ValueListenableBuilder Selector (Provider) Obx (GetX) Example: ValueListenableBuilder( valueListenable: counter, builder: (context, value, child) { return Text('$value'); }, ); const Text("Hello Flutter"); Benefit: Reduces unnecessary rebuilds Improves rendering performance 2. Choose the Right State Management Why it matters: Poor state management = unnecessary UI updates. Recommended: GetX → lightweight, fast Riverpod → scalable Provider → simple apps Tip: Avoid calling setState() for large widgets. 3. Offload Heavy Tasks Using compute() (Multithreading) Why it matters Running heavy tasks on the main thread causes UI freezes and dropped frames. Solution Use compute() to run expensive operations in a separate isolate. Example: import 'package:flutter/foundation.dart'; int heavyTask(int value) { return value * 2; } final result = await compute(heavyTask, 10); Benefit: Smooth UI performance Prevents frame drops Better user experience 4. Optimize Images Why it matters: Large images = memory + performance issues. Best Practices: Use compressed images cacheWidth / cacheHeight Example: Image.network( imageUrl, cacheWidth: 300, ); Bonus: Use cached_network_image for caching. 5. Use ListView.builder for Large Lists Why it matters: Rendering all items at once is expensive. Example: ListView.builder( itemCount: items.length, itemBuilder: (context, index) { return Text(items[index]); }, ); Benefit: Lazy loading Better memory usage 6. Avoid Heavy Work in build() Method Why it matters: build() runs frequently — keep it lightweight. Bad: Widget build(BuildContext context) { final data = fetchData(); // expensive return Text(data); } Good: Future? data; @override void initState() { super.initState(); data = fetchData(); } 7. Use RepaintBoundary to Reduce Repaints Why it matters: Prevents unnecessary repainting of UI parts. Example: RepaintBoundary( child: YourWidget(), ); Use Case: Complex UI Animations Charts 8. Optimize Animations Why it matters: Poor animations = dropped frames. Tips: Use AnimatedContainer instead of manual animation Avoid rebuilding parent widgets during animation Example: AnimatedContainer( duration: Duration(milliseconds: 300), width: isExpanded ? 200 : 100, ); 9. Reduce Widget Tree Depth Why it matters: Deep widget trees increase layout calculation time. Tip: Avoid unnecessary nesting Use helper widgets Bad: Container( child: Padding( child: Align( child: Text("Hello"), ), ), ); Good: Padding( padding: EdgeInsets.all(8), child: Text("Hello"), ); 10. Use Flutter DevTools for Profiling Why it matters: You can’t fix what you can’t measure. Tools: Performance tab Memory tab Widget rebuild stats Command: flutter run --profile What to check: Frame rendering time (16ms target) Jank (frame drops) Memory usage Conclusion Optimizing Flutter performance isn’t about one magic trick — it’s about small, consistent improvements across your app. Key Takeaways: Use const and avoid unnecessary rebuilds Optimize images and lists Keep build() clean Use proper state management Measure performance using DevTools If you apply even 5–6 of these tips, you’ll already notice a huge improvement in your app’s speed and smoothness.

FF Designer: AI-Powered UI Generation for FlutterFlow Builders
Introduction If you’re building apps with FlutterFlow, there’s an exciting new tool you should definitely explore — FF Designer. It’s an AI-powered design tool that can generate high-quality app screens in seconds, while still giving you full control to edit and customize everything. In this article, let’s take a quick look at what FF Designer offers and why it’s a game-changer for developers and designers. What is FF Designer? FF Designer is a newly launched tool by FlutterFlow that uses AI to generate UI screens from natural language prompts. Instead of manually designing every screen, you can simply describe what you want — and the tool creates a ready-to-use UI instantly. Think of it as combining design + AI + FlutterFlow workflow into one powerful experience. Key Features AI-Powered UI Generation Create complete app screens using simple prompts like: “Create a fitness dashboard with stats and progress charts” Within seconds, FF Designer generates a structured, visually appealing layout. Visual Editing (Like FlutterFlow) You can: Modify components visually Adjust layouts, colors, and spacing Customize elements just like you would in FlutterFlow No learning curve — it feels familiar and intuitive. Easy Integration with FlutterFlow Import generated designs directly into your FlutterFlow project Export assets for other workflows This makes it easy to move from idea → design → development seamlessly. Why This Matters This launch reflects a bigger shift: AI is no longer just experimental — it’s becoming a practical productivity tool. With FF Designer: Designers can prototype faster Developers can skip repetitive UI work Teams can move from idea to execution much quicker Inspired by Dreamflow FF Designer builds on concepts introduced in Dreamflow, showing how AI can assist in real-world development workflows — not just generate ideas, but actually help build usable UI. Who Should Use It? FF Designer is perfect for: App developers using FlutterFlow UI/UX designers Startup founders building MVPs Anyone prototyping ideas quickly Try It Yourself You can explore FF Designer here: https://designer.flutterflow.io/ Conclusion FF Designer is a strong step toward the future of app development — where AI assists creativity instead of replacing it. If you’re already using FlutterFlow, this tool can significantly speed up your workflow and help you build better UI faster. Final Thoughts Low-code is evolving. AI is accelerating it. And tools like FF Designer are bringing both together in a powerful way. #FlutterFlow #AI #Mobile Development #UI Design #No Code

Flutter + Firebase Cloud Functions: Complete Guide with Real Examples
Introduction Building modern mobile apps requires more than just a beautiful UI — you also need a reliable backend. This is where Flutter and Firebase Cloud Functions become a powerful combination. Flutter is a UI toolkit by Google that allows you to build natively compiled apps for mobile, web, and desktop using a single codebase. Firebase Cloud Functions is a serverless backend solution that lets you run code in response to events without managing servers. When you combine them, you get: A fast, scalable frontend (Flutter) A powerful, secure backend (Cloud Functions) This guide will walk you through everything — from setup to real-world examples — in a simple and practical way. Why Use Flutter + Firebase Cloud Functions? Key Benefits Feature Benefit Serverless backend No need to manage serversReal-time integrationWorks seamlessly with Firestore Scalability Automatically scales with usersSecurityBackend logic stays hiddenCost-effectivePay only for usage Use Cases Here are some real-world scenarios where this combination shines: 1. Secure Backend Logic Payment verification User authentication checks Role-based access control 2. Notifications System Send push notifications when data changes Trigger alerts on user actions 3. Data Processing Automatically process uploaded data Clean and transform Firestore entries 4. Third-Party API Integration Call external APIs securely (without exposing keys) 5. Scheduled Jobs Daily reports Cleanup tasks Step-by-Step Setup Let’s set up everything from scratch. Step 1: Setup Flutter Project flutter create my_app cd my_app Step 2: Setup Firebase Go to Firebase Console Create a project Add Android/iOS app Download config files: google-services.json (Android) GoogleService-Info.plist (iOS) Step 3: Add Firebase to Flutter Add dependencies: dependencies: firebase_core: ^latest cloud_firestore: ^latest Initialize Firebase: void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(MyApp()); } Step 4: Setup Firebase CLI Install CLI: npm install -g firebase-tools Login: firebase login Initialize functions: firebase init functions Choose: JavaScript or TypeScript ESLint (optional) Step 5: Write Your First Cloud Function Example: Trigger when a user is created in Firestore const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.onUserCreate = functions.firestore .document("users/{userId}") .onCreate((snap, context) => { const data = snap.data(); console.log("New user created:", data); return null; }); Deploy: firebase deploy --only functions Real-World Examples Example 1: Send Push Notification on New Message Cloud Function exports.sendNotification = functions.firestore .document("messages/{id}") .onCreate(async (snap, context) => { const message = snap.data(); const payload = { notification: { title: "New Message", body: message.text, }, }; return admin.messaging().sendToTopic("allUsers", payload); }); Flutter Side Subscribe to topic: FirebaseMessaging.instance.subscribeToTopic("allUsers"); Example 2: Secure Payment Verification Never verify payments on the client side! Cloud Function exports.verifyPayment = functions.https.onCall(async (data, context) => { const paymentId = data.paymentId; // Call payment gateway API const isValid = true; // simulate if (!isValid) { throw new functions.https.HttpsError("failed-precondition", "Invalid payment"); } return { success: true }; }); Flutter Call final callable = FirebaseFunctions.instance.httpsCallable('verifyPayment'); final result = await callable.call({ "paymentId": "12345", }); print(result.data); Example 3: Auto-Update Data (Business Logic) Use Case: When an order is created → update user stats exports.updateUserStats = functions.firestore .document("orders/{orderId}") .onCreate(async (snap, context) => { const order = snap.data(); const userId = order.userId; const userRef = admin.firestore().collection("users").doc(userId); await userRef.update({ totalOrders: admin.firestore.FieldValue.increment(1), }); }); Example 4: Call External API Securely const axios = require("axios"); exports.fetchWeather = functions.https.onCall(async (data, context) => { const city = data.city; const response = await axios.get( `https://api.weatherapi.com/v1/current.json?key=API_KEY&q=${city}` ); return response.data; }); API key stays safe in backend! Best Practices 1. Keep Business Logic in Cloud Functions Don’t trust frontend Always validate on backend 2. Use Environment Config firebase functions:config:set api.key="YOUR_KEY" Access: functions.config().api.key 3. Handle Errors Properly throw new functions.https.HttpsError( "invalid-argument", "Missing data" ); 4. Optimize Performance Avoid heavy loops Use async/await properly Minimize Firestore reads 5. Secure Your Functions Use authentication checks: if (!context.auth) { throw new functions.https.HttpsError("unauthenticated"); } Common Pitfalls 1. Doing Everything in Flutter Leads to security issues 2. Infinite Function Loops Example: Function writes to Firestore Trigger fires again Fix: Use flags or conditions 3. Large Cold Start Delays Happens in unused functions Fix: Use smaller functions Use regional deployment 4. Exposing API Keys Always call APIs via Cloud Functions 5. Not Handling Errors Always use try/catch Pro Tips Use TypeScript for better maintainability Structure functions into modules Log everything using console.log Monitor using Firebase Console Conclusion Flutter + Firebase Cloud Functions is a powerful full-stack solution that allows you to build scalable, secure, and modern applications without managing servers. Key Takeaways: Flutter handles UI beautifully Cloud Functions handle secure backend logic Real-time + serverless = fast & scalable apps Keep sensitive logic off the client Use triggers and callable functions wisely If you’re building apps with features like: Payments Notifications AI integrations Real-time data Then this stack is one of the best choices available today. Final Thought Start simple: Build one function Connect it to Flutter Expand step by step And soon, you’ll be building production-ready apps with confidence

Flutter Navigation Made Simple: Moving Between Screens Without the Confusion
Navigation is one of those things in Flutter that looks simple… until it isn’t. At first, pushing a screen feels straightforward. But as your app grows — multiple flows, authentication states, nested routes — things start getting messy. Back stacks behave unexpectedly, screens duplicate, and users land in places they shouldn’t. We’ve been there. So in this guide, we’re breaking down Flutter navigation in a way that actually makes sense — with real use cases, clean patterns, and common mistakes developers often overlook. The Core Idea of Navigation in Flutter Flutter uses a stack-based navigation system. Think of it like this: Every new screen is pushed onto a stack Going back pops the top screen You can replace, reset, or manipulate the stack as needed Basic Navigation (Push & Pop) Go to a new screen Navigator.push( context, MaterialPageRoute(builder: (context) => SecondScreen()), ); Go back Navigator.pop(context); Replace Current Screen Useful for flows like login → home (you don’t want users going back to login). Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomeScreen()), ); Clear Entire Navigation Stack Used after authentication, onboarding, etc. Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => HomeScreen()), (route) => false, ); Pop Until Specific Screen Navigator.popUntil(context, (route) => route.isFirst); Named Navigation (Clean & Scalable) Instead of repeating routes everywhere, define them once: routes: { '/home': (context) => HomeScreen(), '/profile': (context) => ProfileScreen(), } Navigate Navigator.pushNamed(context, '/profile'); Replace Navigator.pushReplacementNamed(context, '/home'); Clear Stack Navigator.pushNamedAndRemoveUntil( context, '/home', (route) => false, ); Safe Navigation (Avoid Crashes) Check if you can go back if (Navigator.canPop(context)) { Navigator.pop(context); } Safer alternative Navigator.maybePop(context); Navigation Cheat Sheet (Practical Use Cases) Here’s a quick reference we actually use in real projects: Common Mistakes We’ve Seen This is where most developers struggle 👇 1. Using push instead of pushReplacement Problem : Users can go back to login/signup screens Fix : Use pushReplacement after authentication 2. Not clearing stack after login Problem : Back button leads to unwanted screens Fix : Use pushAndRemoveUntil 3. Overusing anonymous routes Problem : Hard to maintain and debug Fix : Switch to named routes for scalability 4. Ignoring back stack behavior Problem : Unexpected navigation flows Fix : Always think: what should happen when user presses back? 5. Calling pop without checking Problem : App crashes if no route exists Fix : Use canPop or maybePop 6. Mixing navigation styles randomly Problem : Inconsistent architecture Fix : Stick to one approach (prefer named routes in bigger apps) 7. Not handling deep navigation flows Problem : Complex flows break easily Fix : Plan navigation structure early (especially for multi-step flows) Practical Insights from Production Experience Keep navigation logic centralized (avoid scattering it everywhere) Use named routes for medium to large apps Think in terms of user journey, not just screens Test navigation like a user — not just as a developer Final Thoughts Flutter navigation isn’t complicated — but it becomes confusing when we don’t structure it properly. Once you understand: Stack behavior When to replace vs push How to reset flows everything starts to click. The key is not just knowing the methods — it’s knowing when to use them.

Google Pay–Like Screenshot Sharing in FlutterFlow
Introduction Have you ever noticed how smoothly Google Pay lets users share a payment screenshot instantly? With just one tap, a clean, perfectly formatted image is generated and shared — no manual screenshots, no cropping, no hassle. I implemented a similar one-tap screenshot sharing feature in FlutterFlow using Custom Actions, and in this article, I’ll walk you through the approach, tools, and benefits. The Problem Before implementing this feature, users typically relied on manual screenshots: Taking screenshots manually Cropping unwanted UI elements Sharing inconsistent or messy images This leads to a poor user experience, especially in apps where sharing data (like payments or receipts) is frequent. The Solution To solve this, we implemented: One-tap screenshot capture Capture only the required UI section Direct sharing via native share sheet All of this was built inside FlutterFlow using Custom Actions, combining low-code UI with custom Flutter logic. How It Works The implementation is simple yet powerful: Wrap the required UI inside a Screenshot widget Use a ScreenshotController to manage capture Trigger the capture on button tap Only the wrapped UI is captured — ensuring clean and consistent output every time. Packages Used We used lightweight and production-ready packages: screenshot → Capture widget as an image path_provider → Store the image temporarily share_plus → Share using native apps This combination keeps the implementation efficient and scalable. Smart UI Handling To ensure professional output, we also handled: Light & Dark mode compatibility Custom background images for better presentation Consistent layout across devices Result: Clean, polished, and share-ready screenshots every time. Use Cases This feature is extremely useful for: Payment confirmations Transaction receipts Order summaries Reports and dashboards It is especially valuable in fintech and utility apps where sharing information is frequent. Why FlutterFlow + Custom Actions This implementation highlights the power of combining: Rapid UI development with FlutterFlow Full flexibility using custom Flutter code Easy integration with native capabilities You truly get the best of boh worlds: speed + control Final Outcome Improved overall user experience Reduced friction in sharing workflows Faster and cleaner content sharing Achieved a Google Pay–like seamless UX Conclusion If you’re building apps in FlutterFlow and want to deliver advanced, polished user experiences — Custom Actions are the key. They allow you to go beyond limitations and implement features that feel truly native and professional. Final Thoughts Low-code doesn’t mean low-power. With the right approach, you can build high-quality, production-ready features that rival top-tier apps like Google Pay. #Flutter #FlutterFlow #Mobile Development #UX Design

Top 10 Flutter Utility Packages Every Developer Should Use
Flutter is incredibly powerful, but what truly boosts productivity is its ecosystem of ready-to-use utility packages. Instead of building everything from scratch, these packages help you: Speed up development Focus on core features Add polished functionality instantly In this guide, we’ll explore 10 highly practical Flutter packages that you’ll actually use in real-world apps. Top 10 Must-Have Flutter Utility Packages 1. cached_network_image https://pub.dev/packages/cached_network_image Description Efficiently loads and caches images from the internet. Key Features Automatic caching Placeholder & error widgets Smooth image loading Use Cases Social media apps E-commerce apps Profile images Example CachedNetworkImage( imageUrl: "https://example.com/image.jpg", placeholder: (context, url) => CircularProgressIndicator(), errorWidget: (context, url, error) => Icon(Icons.error), ); Pros Improves performance Reduces network calls Cons Limited cache control 2. dio https://pub.dev/packages/dio Description A powerful HTTP client for handling APIs. Key Features Interceptors Request cancellation Logging support Use Cases REST API integration Token handling Debugging network calls Example final dio = Dio(); final response = await dio.get('https://api.example.com'); Pros Feature-rich Scalable Cons Slight learning curve 3. path_provider https://pub.dev/packages/path_provider Description Provides access to device storage paths. Key Features App directory access Temporary storage paths Cross-platform support Use Cases Save files locally Cache data Store downloads Example final directory = await getApplicationDocumentsDirectory(); print(directory.path); Pros Essential for file handling Cons Only provides paths 4. file_picker https://pub.dev/packages/file_picker Description Allows users to select files from their device. Key Features Multi-file selection Supports all file types Cross-platform Use Cases Upload documents Media selection Resume uploads Example FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null) { print(result.files.single.path); } Pros Simple and flexible Cons Requires permissions 5. shared_preferences https://pub.dev/packages/shared_preferences Description Stores simple data locally using key-value pairs. Key Features Lightweight storage Persistent data Easy to use Use Cases Save user settings Store login flags Theme preferences Example final prefs = await SharedPreferences.getInstance(); await prefs.setString('username', 'John'); Pros Very easy to implement Cons Not secure for sensitive data 6. image_picker https://pub.dev/packages/image_picker Description Pick images from camera or gallery. Key Features Camera & gallery support Simple API Use Cases Profile picture upload Social apps Image sharing Example final image = await ImagePicker().pickImage(source: ImageSource.gallery); Pros Easy integration Cons Requires permissions 7. flutter_svg https://pub.dev/packages/flutter_svg Description Render SVG images in Flutter apps. Key Features High-quality vector rendering Scalable UI assets Use Cases Icons Logos Illustrations Example SvgPicture.asset('assets/icon.svg'); Pros Sharp UI across devices Cons Complex SVGs may fail 8. connectivity_plus https://pub.dev/packages/connectivity_plus Description Detect internet connectivity status. Key Features WiFi/mobile detection Real-time updates Use Cases Offline UI handling Network monitoring Example var result = await Connectivity().checkConnectivity(); Pros Lightweight Cons Doesn’t guarantee internet access 9. intl https://pub.dev/packages/intl Description Provides internationalization and formatting utilities. Key Features Date formatting Number formatting Localization support Use Cases Multi-language apps Currency formatting Date/time display Example import 'package:intl/intl.dart'; String formattedDate = DateFormat('dd MMM yyyy').format(DateTime.now()); Pros Essential for global apps Cons Slightly verbose setup 10. permission_handler https://pub.dev/packages/permission_handler Description Handles runtime permissions on Android & iOS. Key Features Request/check permissions Supports all major permissions Cross-platform Use Cases Camera access Storage access Location permissions Example var status = await Permission.camera.request(); if (status.isGranted) { print("Camera permission granted"); } Pros Must-have for real apps Cons Platform configuration required Bonus Package : 11. url_launcher https://pub.dev/packages/url_launcher Description Launch URLs, emails, phone calls, and apps. Key Features Open websites Make phone calls Send emails Use Cases Contact buttons Open external links Deep linking Example launchUrl(Uri.parse("https://flutter.dev")); Pros Very versatile Cons Needs platform setup Conclusion Using the right Flutter utility packages can dramatically improve your development workflow. Key Takeaways: Use practical packages like cached_network_image, dio, and shared_preferences Add intl for localization Use permission_handler for real-world permissions With the right tools, you can build apps that are: Faster More efficient Production-ready

Identity Verification in FlutterFlow using uqudo SDK
Overview In modern applications, secure and seamless user onboarding is critical — especially when identity verification (KYC) is involved. In this article, I’ll walk through how we integrated the uqudo SDK Flutter plugin into a FlutterFlow application using Custom Actions to enable a robust identity verification flow. This solution leverages uqudo’s official Android and iOS SDKs to deliver a secure, scalable, and efficient KYC experience — particularly optimized for users across the Middle East & Africa. Objective The goal was to implement a reliable identity verification system in FlutterFlow that: Accelerates user onboarding Reduces manual verification efforts Seamlessly integrates into a no-code / low-code workflow Maintains high security and accuracy Technology Stack FlutterFlow Custom Actions (Flutter code) uqudo SDK Flutter Plugin Android & iOS Native SDKs Device Camera (Front Camera) Architecture & Implementation Approach To integrate uqudo into FlutterFlow, we followed a hybrid approach: The uqudo Flutter plugin was added to the FlutterFlow project Custom Actions were used to bridge FlutterFlow UI with SDK functionality Platform-specific logic was handled in: android/ (native implementation) ios/ (native implementation) This approach allowed us to: Use advanced native SDK features Keep FlutterFlow UI clean and manageable Maintain flexibility for future enhancements Verification Flow 1. Identity Document Scanning We implemented document scanning for: Aadhaar Card PAN Card Using uqudo’s document verification capabilities, the app extracts and validates identity data efficiently. 2. Face Capture & Biometric Verification The device’s front camera is used to capture the user’s face Face matching is performed against the scanned document This ensures: Authenticity Fraud prevention Real-time verification 3. Verification Result Handling Clear outcomes are displayed directly in the UI: Face matched successfully Face mismatch detected This improves transparency and user trust during onboarding. 4. Error Handling & User Feedback Robust error handling was implemented using Custom Actions to manage: Invalid document scans Face mismatch scenarios Camera permission issues SDK-related errors Providing clear feedback significantly improved the user experience. Outcome & Impact Successfully implemented a production-ready KYC flow within FlutterFlow Reduced onboarding friction with automation Enabled seamless integration of native SDKs in a low-code environment Improved user trust with real-time verification feedback Key Learnings FlutterFlow Custom Actions are powerful for integrating complex SDKs Combining low-code UI with custom Flutter logic offers both speed and flexibility Native SDK integration is achievable without compromising maintainability Proper error handling is critical for user trust and retention Conclusion Integrating the uqudo SDK in FlutterFlow using Custom Actions proved to be an effective approach for building a secure and scalable identity verification system. This method bridges the gap between low-code development and advanced native capabilities, enabling faster delivery without sacrificing control or performance. Final Thoughts If you’re building a FlutterFlow app that requires KYC, identity verification, or onboarding automation, this approach can significantly reduce development complexity while ensuring a high-quality user experience. #FlutterFlow #Flutter #MobileDevelopment #KYC #IdentityVerification

Which Flutter State Management Should You Use? (Complete Developer Guide)
Flutter makes building beautiful apps easy — but as your app grows, managing data across screens becomes challenging. You may have faced issues like: UI not updating properly Data not syncing between screens Too many unnecessary rebuilds This is exactly where state management becomes essential. In this guide, we’ll break down everything — from basics to advanced approaches — so you can confidently choose the right solution. What is State Management? In simple terms: State = Any data that changes in your app Examples: Counter value API response User login status Theme (dark/light) State Management = How you manage and update that data efficiently across your app Without proper state management: Your UI becomes unpredictable Code becomes hard to maintain Scaling becomes difficult 1. setState (The Simplest Way) What it is Built-in Flutter method to update UI when state changes. Example : class CounterPage extends StatefulWidget { const CounterPage({super.key}); @override State createState() => _CounterPageState(); } class _CounterPageState extends State { int _count = 0; void _increment() { setState(() { // triggers a rebuild _count++; }); } @override Widget build(BuildContext context) { return Scaffold( body: Center(child: Text('Count: $_count')), floatingActionButton: FloatingActionButton( onPressed: _increment, child: const Icon(Icons.add), ), ); } } When to use : Purely local UI interactions with no cross-widget communication — toggle buttons, form field validation, simple animations, local loading spinners. 2. Provider What it is A wrapper around InheritedWidget for structured state management. Example : // 1. Define a ChangeNotifier class CartProvider extends ChangeNotifier { final List _items = []; List get items => _items; void addItem(String item) { _items.add(item); notifyListeners(); // triggers rebuild in listeners } } // 2. Wrap your tree with ChangeNotifierProvider ChangeNotifierProvider( create: (_) => CartProvider(), child: const MyApp(), ) // 3. Read or watch in any descendant widget final cart = context.watch(); Text('${cart.items.length} items in cart') When to use : Small-to-medium apps with straightforward state that doesn’t need complex async logic. Great for your first real Flutter project beyond tutorials. 3. Riverpod (Modern Approach) What it is A more powerful and safer version of Provider. Example : // pubspec.yaml // riverpod_annotation: ^4.0.2 // riverpod_generator: ^4.0.3 part 'auth_notifier.g.dart'; // Class-based notifier with codegen @riverpod class AuthNotifier extends _$AuthNotifier { @override AuthState build() => const AuthState.initial(); Future signIn(String email, String password) async { state = const AuthState.loading(); try { final user = await AuthService().signIn(email, password); state = AuthState.authenticated(user); } catch (e) { state = AuthState.error(e.toString()); } } } // In a ConsumerWidget — no BuildContext magic needed class AuthScreen extends ConsumerWidget { const AuthScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final authState = ref.watch(authNotifierProvider); return authState.when( initial: () => const LoginScreen(), loading: () => const CircularProgressIndicator(), authenticated: (user) => HomeScreen(user: user), error: (msg) => ErrorView(message: msg), ); } } When to use : Medium-to-large apps where you want clean architecture, excellent async support, and testability without Bloc’s ceremony. Excellent choice for solo developers and small teams building production apps. 4. Bloc / Cubit (Enterprise-Level) What it is A structured pattern using streams. Bloc → Event-driven Cubit → Simpler version Example : // State class class AuthState { final bool isAuthenticated; final String? userId; const AuthState({required this.isAuthenticated, this.userId}); } // Cubit — logic lives here, NOT in the widget class AuthCubit extends Cubit { AuthCubit() : super(const AuthState(isAuthenticated: false)); Future signIn(String email, String password) async { final user = await AuthService.signIn(email, password); emit(AuthState(isAuthenticated: true, userId: user.id)); } void signOut() => emit(const AuthState(isAuthenticated: false)); } // Widget — just listens, zero logic BlocBuilder( builder: (context, state) { return state.isAuthenticated ? const HomeScreen() : const LoginScreen(); }, ) When to use : Large-scale apps with complex business logic, multiple async operations, strict testability requirements, or teams that need predictable, traceable state transitions. Common in enterprise and fintech Flutter apps. 5. GetX (Fast & Lightweight) What it is All-in-one solution (state + routing + dependency injection). Example : // Controller — reactive variables with .obs class ProfileController extends GetxController { final RxString name = ''.obs; final RxBool isLoading = false.obs; Future loadProfile() async { isLoading.value = true; final data = await ApiService().getProfile(); name.value = data.name; isLoading.value = false; } } // Widget — Obx auto-rebuilds when .obs changes class ProfilePage extends GetView { @override Widget build(BuildContext context) { return Obx(() { if (controller.isLoading.value) { return const CircularProgressIndicator(); } return Text(controller.name.value); }); } } // Navigation — no BuildContext needed Get.to(() => const ProfilePage()); Get.back(); When to use : Prototypes, hackathons, small personal projects, or when you need to move very fast and want everything under one roof. Use with caution in large team environments. Real-World Use Cases Small Apps Use: setState Provider Example: Forms, basic apps Medium Apps Use: Provider GetX Example: Dashboard, e-commerce Large Apps Use: Riverpod Bloc Example: Production apps with APIs Team / Enterprise Use: Bloc Riverpod Better maintainability and structure Final Recommendation Beginner Start with: setState → then Provider Intermediate Use: Riverpod (recommended) or GetX Advanced / Production Use: Riverpod (modern + scalable) Bloc (enterprise structure) Final Thoughts There is no single “best” state management solution. The right choice depends on: App complexity Team size Development speed Maintainability needs

Google & Apple Sign-In in Flutter
A production-grade walkthrough: clean auth service, real code from a real app, and integration patterns. Table of Contents Introduction Prerequisites Dependencies & Setup Getting the Server Client ID The Clean AuthService Platform Configuration Common Errors & Fixes UI Example Conclusion 01 / Introduction Why Social Sign-In Still Matters in 2026 Every additional step between a user opening your app and them being inside it is a drop-off point. Password flows are friction. Google and Apple Sign-In are the fastest path from “curious” to “engaged” — two taps and you’re in, no new password to forget. Who this is for Flutter developers at any level who want latest Google and Apple Sign-In that actually works in production. 02 / Prerequisites What You Need Before Starting A Firebase project with Authentication enabled — Google and Apple providers turned on FlutterFire CLI installed and flutterfire configure already run For Apple Sign-In: an Apple Developer account with Sign In with Apple capability enabled For Android Google Sign-In: SHA-1 fingerprint registered in Firebase Console 03 / Dependencies & Setup Packages, pubspec, and Initialization Add to pubspec.yaml dependencies: flutter_dotenv: ^5.2.1 firebase_core: ^3.10.1 firebase_auth: ^5.5.1 google_sign_in: ^7.2.0 sign_in_with_apple: ^7.0.1 flutter: assets: - .env Then run: flutter pub get Create your .env file Store sensitive config outside of source code. Create a .env file in your project root and add it to .gitignore: # Get this from Google Cloud Console → OAuth 2.0 → Web Client (see Section 4) SERVER_CLIENT_ID=123456789-abcdefg.apps.googleusercontent.com Initialize Firebase and Google Sign-In in main.dart This is the most important step people miss, you must call GoogleSignIn.instance.initialize() before runApp(), after Firebase is ready: import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:your_app/service/auth_service.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // 1. Load environment variables await dotenv.load(fileName: '.env'); // 2. Initialize Firebase await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); // 3. Initialize AuthService (which calls GoogleSignIn.instance.initialize) await AuthService().initialize(); runApp(const MyApp()); } Skip initialize() and you’ll get a StateError If you call authenticate() or authorizationClient before initialize(), Flutter throws a StateError: instance not initialized. This crashes silently in release builds. Always initialize first. 04 / Google Cloud Configuration Getting the Server Client ID (Web OAuth Client) The serverClientId is the Web Client ID from Google Cloud Console — not the Android or iOS client. It is required for Google Sign-In on Android and enables server-side token verification. Here’s exactly how to find it: Google Cloud Console — Step-by-step walkthrough Go to console.cloud.google.com and select your Firebase project (same project name as in Firebase Console) In the left sidebar, navigate to APIs & Services → Credentials Under OAuth 2.0 Client IDs, look for the entry with type “Web application”. It is usually auto-created by Firebase and named something like “Web client (auto created by Google Service)” Click the Web application entry to open its details Copy the Client ID field — it ends in .apps.googleusercontent.com . This is your SERVER_CLIENT_ID. Paste it into your .env file as SERVER_CLIENT_ID= Can’t find the Web Client? If you don’t see a Web Client ID, go to Firebase Console → Authentication → Sign-in method → Google → click the expand arrow. Firebase will show you the Web SDK configuration which contains the same client ID. Android vs iOS vs Web — use the Web client There will be separate entries for Android, iOS, and Web in the credentials list. The serverClientId parameterspecifically requires the Web client ID. Using the Android or iOS client ID here is a common mistake that silently fails. 05 / The Clean AuthService Authentication Service Implementation Here’s the authentication logic, cleaned up: lib/service/auth_service.dart import 'dart:developer' as log; import 'dart:math'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart'; /// Clean authentication service — auth logic only, no database concerns. /// Use it as a foundation and add your own data layer on top. class AuthService { // ─── Singleton ─────────────────────────────────────────── static final AuthService _instance = AuthService._internal(); factory AuthService() => _instance; AuthService._internal(); // ─── Firebase + Google ──────────────────────────────────── final FirebaseAuth _auth = FirebaseAuth.instance; final GoogleSignIn _googleSignIn = GoogleSignIn.instance; /// Web Client ID from Google Cloud Console → OAuth 2.0 → Web application String get _serverClientId => dotenv.env['SERVER_CLIENT_ID'] ?? ''; // ─── Public Getters ─────────────────────────────────────── User? get currentUser => _auth.currentUser; bool get isSignedIn => currentUser != null; // ─── Initialization ─────────────────────────────────────── /// Call once at app startup, after Firebase.initializeApp(). /// Required by google_sign_in v7+ before any sign-in call. Future initialize() async { try { await _googleSignIn.initialize(serverClientId: _serverClientId); log.log('[AuthService] Google Sign-In initialized'); } catch (e) { log.log('[AuthService] Google init error: $e'); rethrow; // fail fast — misconfiguration should be caught at startup } } // ─── Google Sign-In ─────────────────────────────────────── /// Signs in with Google and returns a Firebase [UserCredential]. /// Throws on cancellation or error — catch in your controller/notifier. Future signInWithGoogle() async { // Sign out first — ensures the account picker is always shown await _googleSignIn.signOut(); // 1. Trigger Google authentication — shows the account picker final GoogleSignInAccount googleUser = await _googleSignIn.authenticate(scopeHint: ['email']); // 2. Get the ID token directly from the authenticated account final GoogleSignInAuthentication googleAuth = googleUser.authentication; // 3. Also get the access token from the authorization client (for scopes) final authClient = _googleSignIn.authorizationClient; final authorization = await authClient.authorizationForScopes(['email', 'profile']); // 4. Build the Firebase credential from both tokens final credential = GoogleAuthProvider.credential( idToken: googleAuth.idToken, accessToken: authorization?.accessToken, ); // 5. Sign into Firebase — creates the user on first login automatically return _auth.signInWithCredential(credential); } // ─── Apple Sign-In ──────────────────────────────────────── /// Signs in with Apple ID and returns a Firebase [UserCredential]. /// Throws on cancellation or error — catch in your controller/notifier. Future signInWithApple() async { // 1. Generate a cryptographically random nonce (replay-attack protection) final rawNonce = _generateNonce(); // 2. Request Apple credential — opens the system Sign-In sheet final appleCredential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], ); // 3. Build the Firebase OAuthCredential using Apple's identity token final oAuthCredential = OAuthProvider('apple.com').credential( idToken: appleCredential.identityToken, rawNonce: rawNonce, accessToken: appleCredential.authorizationCode, ); // 4. Sign into Firebase return _auth.signInWithCredential(oAuthCredential); } // ─── Sign Out ───────────────────────────────────────────── /// Signs out from both Firebase and Google simultaneously. Future signOut() async { await Future.wait([ _auth.signOut(), _googleSignIn.signOut(), ]); } // ─── Error Messages ─────────────────────────────────────── /// Converts a FirebaseAuthException into a user-readable message. static String getFirebaseErrorMessage(FirebaseAuthException e) { switch (e.code) { case 'user-not-found': return 'No account found with this email.'; case 'wrong-password': return 'Incorrect password.'; case 'email-already-in-use': return 'This email is already registered.'; case 'invalid-email': return 'Please enter a valid email.'; case 'weak-password': return 'Password is too weak.'; case 'too-many-requests': return 'Too many attempts. Try again later.'; case 'network-request-failed': return 'No internet connection.'; case 'operation-not-allowed': return 'This sign-in method is not enabled.'; case 'account-exists-with-different-credential': return 'An account with this email exists with a different sign-in method.'; default: return 'Authentication failed. Please try again.'; } } // ─── Nonce Generator (Apple Sign-In) ───────────────────── /// Generates a cryptographically secure random string. /// Apple uses this to prevent replay attacks on the identity token. String _generateNonce([int length = 32]) { const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; final random = Random.secure(); return List.generate(length, (_) => charset[random.nextInt(charset.length)]).join(); } } 06 / Platform Configuration Android & iOS Setup Android — Google Sign-In 1. Get your SHA-1 fingerprint # Debug keystore (development) keytool -list -v \ -keystore ~/.android/debug.keystore \ -alias androiddebugkey \ -storepass android -keypass android # Copy the SHA1 line from the output, e.g.: # SHA1: A1:B2:C3:D4:E5:F6:... Add this SHA-1 in Firebase Console → Project Settings → Your Android app → Add fingerprint. Then re-download google-services.json and place it at android/app/google-services.json. Add both debug and release SHA-1 The debug SHA-1 works only during development. For production (Play Store), add the SHA-1 from yourupload keystore. Missing the release SHA-1 causes silent failures after publishing. 2. Verify build.gradle files android/build.gradle buildscript { dependencies { classpath 'com.google.gms:google-services:4.4.2' } } android/app/build.gradle // Must be at the very bottom of the file apply plugin: 'com.google.gms.google-services' iOS — Google Sign-In Add the reversed client ID URL scheme Open GoogleService-Info.plist, find the REVERSED_CLIENT_ID value, then add it to ios/Runner/Info.plist: ios/Runner/Info.plist CFBundleURLTypes CFBundleTypeRole Editor CFBundleURLSchemes com.googleusercontent.apps.YOUR_REVERSED_CLIENT_ID iOS — Apple Sign-In 1. Enable the capability in Xcode Open ios/Runner.xcworkspace in Xcode → select Runner target → Signing & Capabilities → + Capability → Sign In with Apple. 2. Enable in Apple Developer Portal Log into developer.apple.com → Identifiers → select your App ID → check Sign In with Apple → Save. Regenerate your provisioning profile. 3.Enable in Firebase Console Firebase Console → Authentication → Sign-in method → Apple → Enable. Paste your App ID (e.g. com.company.app) as the Service ID. 4.Add the entitlement (if needed) Xcode usually handles this automatically when you add the capability. Verify Runner.entitlements contains com.apple.developer.applesignin with value Default. Apple Sign-In on Android sign_in_with_apple supports Android via a web-based OAuth flow. You need to configure a web redirect URL in Apple Developer Console and add it to the plugin configuration. See the package README for the full Android setup guide. 07 / Debugging Common Errors & Exact Fixes 1. StateError: instance not initialized Root Cause: GoogleSignIn.instance is used before calling initialize() Fix: Make sure to call and await AuthService().initialize() inside main() before runApp() 2. sign_in_failed (Android) Root Cause: SHA-1 fingerprint is missing or incorrect Fix: Add both debug and release SHA-1 in Firebase Console, then re-download google-services.json 3. PlatformException: sign_in_canceled Root Cause: User closed the Google account picker Fix: This is expected behavior — handle it silently without showing an error toast 4. operation-not-allowed Root Cause: Google Sign-In is not enabled in Firebase Fix: Go to Firebase Console → Authentication → Sign-in method → Enable Google 5. idToken is null Root Cause: Authentication failed or was canceled silently Fix: Always check googleAuth.idToken != null before creating credentials 6. Missing REVERSED_CLIENT_ID (iOS) Root Cause: URL scheme is not configured in Info.plist Fix: Add CFBundleURLSchemes using the REVERSED_CLIENT_ID from GoogleService-Info.plist 7. AuthorizationError: canceled (Apple) Root Cause: User canceled Apple Sign-In Fix: Catch SignInWithAppleAuthorizationException and ignore when e.code == AuthorizationErrorCode.canceled 8. Apple name is null (returning user) Root Cause: Apple only provides the user’s name during the first sign-in Fix: Save the name in your database when isNewUser == true and reuse it later 9. account-exists-with-different-credential Root Cause: Same email is used with another authentication provider Fix: Use fetchSignInMethodsForEmail() and guide the user to link accounts 10. Apple Sign-In not working on Simulator Root Cause: iOS Simulator does not support Apple Sign-In Fix: Always test Apple Sign-In on a real device 08 / UI Example /// GOOGLE LOGIN Future loginWithGoogle() async { setState(() => isLoading = true); final result = await AuthService().signInWithGoogle(); setState(() => isLoading = false); if (result.isSuccess) { _showMessage("Google Login Success ✅"); } else { _showMessage(result.error ?? "Error"); } } /// APPLE LOGIN Future loginWithApple() async { setState(() => isLoading = true); final result = await AuthService().signInWithApple(); setState(() => isLoading = false); if (result.isSuccess) { _showMessage("Apple Login Success 🍎"); } else { _showMessage(result.error ?? "Error"); } } 09 / Conclusion Summary & Best Practices Here’s the complete checklist for production-ready social sign-in: Initialize once — call AuthService().initialize() in main() after Firebase and before runApp() Server Client ID = Web Client — get the Web application client from Google Cloud Console, not Android or iOS Sign out Google on each sign-in — call _googleSignIn.signOut() before authenticating so the picker always appears Both tokens for Firebase — always pass both idToken and accessToken to GoogleAuthProvider.credential() Use a secure nonce for Apple — generate it with Random.secure(), always pass rawNonce to the Firebase credential Save Apple name immediately — it’s only available on the first sign-in; save it to your database right after isNewUser == true Detect new vs returning users — use userCredential.additionalUserInfo?.isNewUser to branch your post-auth flow Sign out from both — always call both _auth.signOut() and _googleSignIn.signOut() on logout SHA-1: debug + release — add both fingerprints to Firebase or Google Sign-In breaks in production builds Test Apple on a real device — iOS Simulator does not support Apple Sign-In.

Flutter Zoom Meeting Wrapper
In today’s connected world, video conferencing has become an essential part of our daily lives. As mobile app developers, integrating reliable video conferencing capabilities can significantly enhance the user experience of your applications. The Flutter Zoom Meeting Wrapper is a powerful Flutter plugin that allows you to seamlessly integrate the Zoom Meeting SDK into your Flutter applications. This means your users can join and participate in Zoom meetings directly within your app without ever needing to switch to the Zoom application. Key Features This plugin offers a range of capabilities to enhance your Flutter application: 🚀 Seamless Integration: Easy integration with the Zoom Meeting SDK 🔄 Simple Initialization: Initialize the SDK using a JWT token 🎯 In-App Experience: Join meetings directly within your app (no Zoom app required) 📱 Platform Support: Complete Android platform compatibility 🔊 Rich Meeting Experience: Full audio and video meeting functionality 🔐 Secure Authentication: Robust security through JWT authentication flow Getting Started Installation To begin using the Flutter Zoom Meeting Wrapper in your project, add the following to your pubspec.yaml file: dependencies: flutter_zoom_meeting_wrapper: ^0.0.1 Run flutter pub get to install the package. Mandatory Zoom SDK Setup For the plugin to function correctly, you need to set up the Zoom SDK: Download the Zoom SDK ZIP from this link Extract the ZIP file after downloading Copy the libs folder and paste it inside your Flutter pub-cache directory at: ~/.pub-cache/hosted/pub.dev/flutter_zoom_meeting_wrapper-0.0.1/android/ Note: Replace 0.0.1 with the version you’re using, if different. 4. Alternatively, run the following command to open the folder directly: open ~/.pub-cache/hosted/pub.dev/flutter_zoom_meeting_wrapper-0.0.1/android ⚠️ Important: The libs folder must be placed in the correct location for the plugin to function properly. Setting Up Zoom API Credentials To use the Zoom Meeting SDK in your application, you’ll need to: Create a Zoom Developer Account at Zoom Marketplace Create a new app in the Zoom Marketplace Obtain your API Key and API Secret from the app credentials page Use these credentials to generate your JWT token Generating a JWT Token You can generate a Zoom JWT token using jwt.io with the following payload and signature: Payload: json{ "appKey": "ZOOM-CLIENT-KEY", "iat": ANY-TIME-STAMP, "exp": ANY-TIME-STAMP, // greater than iat "tokenExp": ANY-TIME-STAMP // greater than iat} Verify Signature: HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), "ZOOM-CLIENT-SECRET") Implementation Guide Initializing the SDK First, initialize the Zoom SDK with your JWT token: import 'package:flutter_zoom_meeting_wrapper/flutter_zoom_meeting_wrapper.dart';// Initialize Zoom SDKbool isInitialized = await ZoomMeetingWrapper.initZoom(jwtToken); Joining a Meeting Once initialized, you can join a Zoom meeting with this simple code: bool joinSuccess = await ZoomMeetingWrapper.joinMeeting( meetingId: "your_meeting_id", meetingPassword: "meeting_password", displayName: "Your Name",); Troubleshooting Common Issues When implementing the Flutter Zoom Meeting Wrapper, you might encounter these common issues: JWT Token Invalid: Ensure your API Key and Secret are correct, and verify that your system time is accurate. Failed to initialize SDK: Check that you have a stable internet connection and are using a valid JWT token. Cannot join meeting: Double-check that the meeting ID and password are correct. Current Limitations While the Flutter Zoom Meeting Wrapper provides powerful functionality, be aware of these current limitations: 🖼️ Custom UI overlays are not supported in the current version 📹 Meeting recording functionality is not available in this plugin 🖥️ Screen sharing capabilities are limited to platform capabilities Conclusion The Flutter Zoom Meeting Wrapper offers a straightforward way to integrate Zoom’s powerful meeting capabilities into your Flutter applications. With minimal setup and easy-to-use API, you can enhance your app with professional video conferencing features. By providing users with the ability to join meetings without leaving your app, you create a more seamless and integrated experience that keeps users engaged with your application.

Flutter Plugin vs Flutter Package: What’s the Difference?
As Flutter developers, we often use the terms plugin and package interchangeably. However, they are not the same thing. Understanding the distinction between the two is important when developing or choosing the right tool for your app. In this article, we’ll explore the key differences, use cases, and when to choose one over the other. 📦 What is a Flutter Package? A Flutter package is a collection of Dart code and assets (like images, fonts, etc.) that adds functionality to a Flutter app. Packages help developers avoid reinventing the wheel by providing reusable solutions for common problems. 🔑 Key Characteristics: Written entirely in Dart. Does not include any native platform-specific code (e.g., no Java/Kotlin for Android or Objective-C/Swift for iOS). Can contain widgets, utilities, models, state management solutions, and more. Works purely within the Flutter framework. 🌟 Examples: 🧩 provider (state management) 🌐 http (network requests) 💾 shared_preferences (basic key-value storage without heavy native dependencies) 🔌 What is a Flutter Plugin? A Flutter plugin is a special type of package that provides an interface between Dart code and platform-specific code (Android, iOS, Web, Desktop). Plugins are needed when Flutter apps need to access platform services, sensors, or APIs that are outside the Flutter framework. 🔑 Key Characteristics: Includes Dart code and platform-specific native code. Uses platform channels to communicate between Flutter and native layers. Needed when you require access to hardware features or native platform APIs (e.g., camera, GPS, file system). 🌟 Examples: 📸 camera (access device camera) 🗺️ google_maps_flutter (display Google Maps) 📱 device_info_plus (fetch device hardware info) 🔍 How to Identify if It’s a Package or Plugin? When browsing pub.dev: If you see “Plugin” tag: it’s a Flutter Plugin (native code included). If you only see “Package” tag: it’s a Dart-only Flutter Package. You can also look at the repository: A plugin will usually have folders like android/, ios/, web/, macos/, windows/, or linux/. A Dart-only package typically has only lib/, test/, and maybe assets/. Thank you for reading!

Struggling with Icloud Data Sync Issues? Let iCloud_Storage_Sync Handle It!
In the ever-evolving world of mobile app development, providing a seamless user experience across multiple devices is no longer a luxury — it’s a necessity. Enter the iCloud_Storage_Sync plugin, a game-changing solution for Flutter developers looking to harness the power of iCloud in their iOS applications. This comprehensive guide will walk you through everything you need to know about this powerful tool and how it can elevate your app to new heights. 🛠 Setting Up iCloud Container: A Step-by-Step Guide Before diving into the features and implementation of the iCloud_Storage_Sync plugin, it’s crucial to properly set up your iCloud Container. Here’s a detailed walkthrough: 1. 👤 Access Your Apple Developer Account Log in and navigate to ‘Certificates, IDs & Profiles’. 2. 🆔 Create Necessary IDs Set up an App ID (if you haven’t already) and create an iCloud Containers ID. 3. 🔗 Link iCloud Container to Your App Assign the iCloud Container to your App ID in the Apple Developer portal. 4. 💻 Configure Xcode Enable the iCloud capability in your Xcode project and select your container. Following these steps ensures that your app is properly set up to use iCloud storage, paving the way for seamless integration with the iCloud_Storage_Sync plugin. 🌟 Introduction: Bridging Flutter and iCloud The iCloud_Storage_Sync plugin is designed to simplify the integration of iCloud storage capabilities into your Flutter iOS apps. By leveraging this plugin, you can offer your users: – 🔄 Effortless backup and synchronization of app data– 📱💻 A consistent user experience across all their Apple devices– 🔒 Secure storage and retrieval of important information– ☁️ Seamless integration with the iCloud ecosystem Whether you’re building a note-taking app, a photo storage solution, or any application that benefits from cloud synchronization, iCloud_Storage_Sync provides the tools you need to create a robust, user-friendly experience. ✨ Features: A Deep Dive Let’s explore the core features that make iCloud_Storage_Sync a must-have for your Flutter iOS project: 1. 📂 Get iCloud FilesRetrieve files stored in iCloud with ease. This feature allows your app to access user data across devices, ensuring a consistent experience no matter where they log in. 2. ⬆️ Upload Files to iCloudEmpower your users to store their important files securely in the cloud. With simple upload functionality, you can offer peace of mind and accessibility. 3. ✏️ Rename iCloud FilesProvide users with the flexibility to organize their cloud storage. The ability to rename files directly within your app adds a layer of convenience to file management. 4. 🗑️ Delete iCloud FilesKeep cloud storage tidy with straightforward file deletion. This feature ensures users can manage their storage space efficiently. 5. ↔️ Move iCloud FilesEnhance file organization by allowing users to move files between folders in their iCloud storage, all from within your app. These features combine to create a comprehensive iCloud management system within your Flutter app, offering users the full power of cloud storage at their fingertips. 🚀 Getting Started: From Installation to Implementation Step 1: 🛠️ InstallationBegin by adding the iCloud_Storage_Sync plugin to your ‘pubspec.yaml’ file: dependencies: icloud_storage_sync: ^0.0.1 Step 2: ⚙️ Install the PluginRun the following command in your terminal: “flutter pub get” Step 3: 💻 Usage in Your Dart CodeImport the plugin in your Dart files: import 'package:icloud_storage_sync/icloud_storage_sync.dart'; With these simple steps, you’re ready to start integrating iCloud functionality into your Flutter app. 📋 Prerequisites: Setting the Stage for Success Before diving into implementation, ensure you have the following in place: – ☑️ An active Apple Developer account– ☑️ A registered App ID and iCloud Container ID– ☑️ iCloud capability enabled and assigned to your app– ☑️ iCloud capability properly configured in Xcode 🧰 API Examples: Bringing iCloud to Life in Your App Let’s explore how to implement each of the core features in your Flutter app: 📥 Getting iCloud FilesRetrieve a list of files stored in iCloud: Future> getCloudFiles({required String containerId}) async { return await icloudSyncPlugin.getCloudFiles(containerId: containerId);} 📤 Uploading Files to iCloudUpload files to iCloud with progress tracking: Future upload({ required String containerId, required String filePath, String? destinationRelativePath, StreamHandler? onProgress,}) async { await icloudSyncPlugin.upload( containerId: containerId, filePath: filePath, destinationRelativePath: destinationRelativePath, onProgress: onProgress, );} 🏷️ Renaming iCloud FilesAllow users to rename their files in iCloud: Future rename({ required String containerId, required String relativePath, required String newName,}) async { await icloudSyncPlugin.rename( containerId: containerId, relativePath: relativePath, newName: newName, ); } 🗑️ Deleting iCloud FilesImplement file deletion functionality: Future delete({ required String containerId, required String relativePath,}) async { await icloudSyncPlugin.delete( containerId: containerId, relativePath: relativePath, );} 🔀 Moving iCloud FilesEnable users to organize their files by moving them within iCloud: Future move({ required String containerId, required String fromRelativePath, required String toRelativePath, }) async { await IcloudSyncPlatform.instance.move( containerId: containerId, fromRelativePath: fromRelativePath, toRelativePath: toRelativePath, );} These code snippets demonstrate the simplicity and power of the iCloud_Storage_Sync plugin. With just a few lines of code, you can implement robust cloud storage features in your Flutter app. 🚀 Real-World Applications: Unleashing the Potential The iCloud_Storage_Sync plugin opens up a world of possibilities for your Flutter iOS app. Here are some practical applications: 1. 📝 Note-Taking Apps: Sync notes across devices, ensuring users always have access to their latest thoughts.2. 📸 Photo Storage Solutions: Offer seamless backup and access to photos across all Apple devices.3. 📚 Document Management: Create a robust system for storing, organizing, and accessing important documents in the cloud.4. 🎮 Game Progress Sync: Keep game saves and progress in sync, allowing users to pick up where they left off on any device.5. 📅 Productivity Apps: Synchronize tasks, calendars, and reminders to keep users organized across their Apple ecosystem. By implementing iCloud sync, you’re not just adding a feature — you’re enhancing the overall user experience and adding significant value to your app. 🤝 Contributing: Join the Community The iCloud_Storage_Sync plugin is an open-source project, and we welcome contributions from the developer community. Whether you’re fixing bugs, improving documentation, or adding new features, your input is valuable. Check out our [GitHub repository] icloud_storage_sync to get started. Don’t forget to review our contribution guidelines to ensure a smooth collaboration process. 🌟 Conclusion: Elevate Your Flutter App with iCloud Integration The iCloud_Storage_Sync plugin represents a significant leap forward for Flutter developers looking to create seamless, cloud-connected iOS applications. By leveraging the power of iCloud, you can offer your users a premium experience that keeps their data secure, accessible, and in sync across all their Apple devices. From simple file storage to complex data synchronization, this plugin provides the tools you need to take your app to the next level. As the mobile app landscape continues to evolve, staying ahead of the curve with features like cloud integration is crucial for success. We invite you to explore the iCloud_Storage_Sync plugin, integrate it into your projects, and experience firsthand the power of seamless cloud synchronization in your Flutter iOS apps. Your users — and your app’s success — will thank you. Ready to get started? Download the plugin now and join the ranks of developers offering top-tier cloud integration in their Flutter apps! For more information, check out the below link

Struggling with Twilio Voice Call Integration in Flutter? twilio_voice_flutter Solves It!
The twilio_voice_flutter plugin simplifies integration with Twilio’s Programmable Voice SDK, enabling VoIP calling within your Flutter apps. It supports both iOS and Android, offering an easy-to-use API for managing calls. Ideal for customer service, communication, or any app needing real-time voice, it leverages Twilio’s reliable infrastructure to deliver high-quality VoIP features. Getting started Add dependency to your pubspec.yaml file & run Pub get dependencies: twilio_voice_flutter: ^0.0.3 And import package into your class file import 'package:twilio_voice_flutter/twilio_voice_flutter.dart'; Important Note ⚠️ This plugin requires Firebase setup for Twilio voice calls! It uses FCM tokens for handling calls on Android 📲 and VoIP notifications for iOS 📞. Ensure both platforms are properly configured for smooth call functionality. ⚠️ Platform Setup AndroidTo integrate the Twilio Voice plugin into your Android project, follow these steps: Open your project’s AndroidManifest.xml file. Add the following service declaration inside the tag: ... android:name="com.twilio.voice.flutter.fcm.VoiceFirebaseMessagingService" android:exported="false" android:stopWithTask="false"> ... iOSTo configure your iOS project to support VoIP calls, follow these steps: Open your project in Xcode. Select your project from the Project Navigator. Go to the Signing & Capabilities tab. Enable the following Background Modes: Audio, AirPlay, and Picture in Picture: Allows your app to continue playing audio while in the background. Voice over IP: Enables your app to receive incoming VoIP calls while in the background. Ensure that your Info.plist file includes the required keys: UIBackgroundModes audio voip 🔑 Twilio Voice Call Access Token Setup This plugin supports Twilio voice calls for both Android and iOS. To generate the access token and enable Twilio calls, follow the steps in the official Twilio repositories: https://github.com/twilio/voice-quickstart-android https://github.com/twilio/voice-quickstart-ios These repositories provide detailed instructions for generating access tokens and making voice calls through Twilio on both Android and iOS platforms. ⚡ Make sure to follow the steps outlined to successfully integrate Twilio voice functionality into your application. Setting Up Twilio Token The setTwilioToken function is used to register a user’s identity with Twilio Voice using the provided access token. This function handles the retrieval of the Firebase Cloud Messaging (FCM) token on Android devices and registers the user with Twilio Voice. static Future setTwilioToken(String identity, String accessToken) async { try{ String accessToken = await _getAccessToken(identity); if (Platform.isAndroid) { String? fcmToken = await FirebaseMessaging.instance.getToken() ?? ""; await TwilioVoiceFlutter.register( identity: identity, accessToken: accessToken, fcmToken: fcmToken); } else { await TwilioVoiceFlutter.register( identity: identity, accessToken: accessToken, fcmToken: ""); } return true; }catch(_){ return false; }} 🔗 Visit example for more info… 😊 Features The Twilio Voice Plugin for Flutter enables seamless integration of voice-over-IP (VoIP) calling into your Flutter applications. Below are the key features supported by this plugin: 1. VoIP Call ManagementInitiate Calls: Easily start a VoIP call to any recipient using the makeCall method, with the ability to pass custom call data. Initiate Calls: Easily start a VoIP call to any recipient using the makeCall method, with the ability to pass custom call data. Receive Incoming Calls: Handle incoming call invites via push notifications, and answer calls using built-in CallKit support on iOS. Call Status Notifications: Stay updated on call status changes such as ringing, connecting, and disconnecting through Flutter MethodChannel callbacks. 2. In-Call Controls Mute/Unmute Calls: Toggle the mute status of the ongoing call using the toggleMute method. Check if the call is currently muted with the isMuted method. Speakerphone Control: Switch between the device’s built-in speaker and receiver during an ongoing call using toggleSpeaker. Verify the current audio route with isSpeaker. 3. CallKit Integration for iOS CallKit Support: Utilize native CallKit functionality on iOS for managing incoming and outgoing VoIP calls, ensuring a familiar user experience. Incoming Call Handling: Report incoming calls to CallKit, allowing the system to display the native call UI and handle interruptions correctly. Background VoIP Support: Ensure your app can receive VoIP calls while in the background by enabling the necessary background modes and configuring the Info.plist accordingly. 4. Push Notification Support VoIP Push Notifications: Register and handle VoIP push notifications via Firebase Cloud Messaging (FCM) on Android and Apple Push Notification service (APNs) on iOS. Push Credential Management: Manage device and access tokens required for receiving VoIP push notifications, ensuring reliable communication. 5. DTMF (Dual-tone Multi-frequency) Signaling Send DTMF Digits: During an active call, send DTMF tones (e.g., for interacting with automated phone systems) using the sendDigits method. 6. Contact Management Custom Contact Data: Store and retrieve custom contact data (like display names and photo URLs) to enhance the calling experience with personalized information. 7. Persistent Data Storage Token and Contact Data Persistence: Securely store and retrieve access tokens and contact data using UserDefaults on iOS to maintain state across app sessions. 8. Call Handling with Error Management Graceful Error Handling: Comprehensive error handling ensures that issues like token expiration or failed call connections are managed and reported to the user effectively. With these features, the Twilio Voice Plugin provides a robust foundation for integrating voice communication into your Flutter applications, supporting a wide range of use cases from customer support to in-app communication. Function Overview registerTwilio(): Registers the device with Twilio using the access token and device token for VoIP push notifications. unregisterTwilio(): Unregisters the device from Twilio VoIP push notifications, removing the access token and device token. makeCall(String to): Initiates a voice call to the specified recipient. If an active call exists, it returns an error. toggleMute(): Toggles the mute status of the ongoing call. Notifies the Flutter side of the change. isMuted(): Returns the current mute status of the ongoing call. toggleSpeaker(): Toggles the speaker mode during an ongoing call. Notifies the Flutter side of the change. isSpeaker() -> Bool: Checks if the speaker mode is currently active. hangUp(): Ends the current call. If no active call exists, it clears the call-related data. activeCall(): Returns details of the active call if one exists. sendDigits(String digits): Sends DTMF digits during an active call.

Effortless Dart Coding with dart_extensions_pro
Introduction Introducing dart_extensions_pro a Dart package that offers a collection of handy extensions and helper functions designed to enhance the development process. By simplifying common tasks and providing streamlined solutions, it allows developers to write code more efficiently and focus on building features rather than repetitive tasks. Ideal for improving productivity, this package is a valuable tool for both novice and experienced programmers. Key Features 📊 Comparison: Simplify comparison operations with intuitive extension methods. 📅 Date Handling: Effortlessly manage date and time with a variety of helpful functions. ✍️ String Utilities: Enhance string manipulation with powerful utility functions. 📋 List Enhancements: Improve list handling with convenient extensions for common operations. 🧭 Navigation: Streamline navigation tasks with specialized navigation functions. 👆 Tap Gestures: Easily handle tap gestures to improve user interaction. 🔁 Iterable Enhancements: Optimize iterable processing with enhanced methods. 🎨 Color Conversion: Simplify color manipulations and conversions with dedicated functions. 🔢 Number Utilities: Access a range of number-related utilities for calculations and formatting. 🛠️ Utility Functions: Utilize various handy utility functions to simplify your coding experience. Installation Add dependency to your pubspec.yaml file & run Pub get dependencies: dart_extensions_pro: ^0.0.1 And import package into your class file import 'package:dart_extensions_pro/dart_extensions_pro.dart'; Analytics Visit EXTENSIONS.md for a complete list of all the available extensions. Extensions: 271Helper Classes: 7Helper Functions & Getters: 21Typedefs: 7Mixins: 2 Here’s a quick preview of dart_extensions_pro, String extension 'hello'.iscapitalize(); // Capitalizes first letter // Hello'Copy this text'.copyTo(); // Copies string to clipboard'test@example.com'.isValidEmail(); // Checks if valid email // true'flutter'.reverse(); // Reverses string // rettulf'madam'.isPalindrome(); // Checks for palindrome // true'flutter example'.toCamelCase(); // Converts to camel case // FlutterExample'{"name": "Flutter"}'.decodeJson(); // Parses JSON string to map // {name: Flutter} Comparison extension 5.gt(3); // true, checks if 5 is greater than 33.lt(5); // true, checks if 3 is less than 55.eq(5); // true, checks if 5 is equal to 53.lte(3); // true, checks if 3 is less than or equal to 35.gte(3); // true, checks if 5 is greater than or equal to 35.ne(3); // true, checks if 5 is not equal to 3 Date extension DateTime.now().isSameDate(DateTime(2023, 9, 14)); // true, checks if today matches the provided dateDateTime.now().isToday(); // true, checks if today is todayDateTime.now().isTomorrow(); // true, checks if today is tomorrow (unlikely)DateTime.now().wasYesterday(); // true, checks if today is yesterday (false)DateTime.now().addDays(5); // adds 5 days to the current dateDateTime.now().addMonths(3); // adds 3 months to the current dateDateTime.now().addYears(2); // adds 2 years to the current dateDateTime.now().subtractDays(7); // subtracts 7 days from the current dateDateTime.now().subtractMonths(1); // subtracts 1 month from the current dateDateTime.now().subtractYears(1); // subtracts 1 year from the current date List extension final list = [1, 2, 3] list.replaceFirstWhere(10, (item) => item == 2); // true, replaces the first occurrence of 2 with 10list.replaceLastWhere(20, (item) => item > 1); // true, replaces the last item greater than 1 with 20 Navigation extension context.to(MyPage()); // Navigates to `MyPage` using `to()`context.toNamed('/home'); // Navigates to the named route '/home' using `toNamed()`context.back(); // Pops the current route using `back()`context.backUntil((route) => route.isFirst); // Pops routes until the first one using `backUntil()`context.toWithReplace(AnotherPage()); // Replaces current route with `AnotherPage` using `toWithReplace()`context.replaceWithNamed('/dashboard'); // Replaces the current route with named route '/dashboard' using `replaceWithNamed()`context.toAndRemoveAll(HomePage(), (route) => false); // Navigates to `HomePage` and removes all previous routes using `toAndRemoveAll()`context.toNamedAndRemoveAll('/login', (route) => false); // Navigates to named route '/login' and removes all previous routes using `toNamedAndRemoveAll()` Gesture extension widget.onInkTap(() => 'Tapped!'.logMsg()); // Adds an ink splash effect with `onInkTap()`widget.onTap(() => 'Tapped!'.logMsg()); // Adds a basic tap gesture with `onTap()`widget.onDoubleTap(() => 'Double Tapped!'.logMsg()); // Adds a double-tap gesture with `onDoubleTap()`widget.onTapCancel(() => 'Tap Cancelled!'.logMsg()); // Adds a tap cancel gesture with `onTapCancel()`widget.onLongPress(() => 'Long Pressed!'.logMsg()); // Adds a long press gesture with `onLongPress()`widget.onTapDown((details) => 'Tap Down!'.logMsg()); // Adds a tap down gesture with `onTapDown()`widget.onScale( onScaleStart: (details) => 'Scale Started!'.logMsg(), onScaleUpdate: (details) => 'Scaling!'.logMsg(), onScaleEnd: (details) => 'Scale Ended!'.logMsg(),); // Adds a scale gesture with `onScale()` Iterable extension iterable.lastElementIndex; // Returns the index of the last element or -1 if empty.iterable.hasSingleElement; // Checks if the iterable has exactly one element.iterable.addAllMatchingTo(targetList, (e) => e.isEven); // Adds elements matching the predicate to the target list.iterable.whereFilter((e) => e.isEven); // Filters elements matching the predicate.iterable.whereFilterIndexed((index, e) => index % 2 == 0); // Filters elements with their index.iterable.mapTransform((e) => e.toString()); // Transforms each element and maps to a new iterable.iterable.skipElements(2); // Skips the first 2 elements.iterable.takeLastElements(2); // Takes the last 2 elements.iterable.skipWhileElements((e) => e iterable.skipLastElements(2); // Skips the last 2 elements. Color conversion String.toColor(); // Converts a hex color string to a Color object, assuming full opacity.HexColor.getColorFromHex(hexColor); // Converts a hex color string to an integer color value, adding alpha if missing.HexColor(hexColor); // Creates a HexColor instance from a hex color string. Number conversion num.negative; // Converts positive numbers to their negative counterparts.num.isBetween(value1, value2, {inclusive = false}); // Checks if [this] is between [value1] and [value2], inclusive if [inclusive] is true.num.roundToDecimals(decimalPlaces); // Rounds the number to [decimalPlaces] decimal places.double.asRadians; // Converts degrees to radians.double.asDegrees; // Converts radians to degrees.T.maxim(upperBound, {exclusive = false}); // Limits the value to [upperBound], exclusive if [exclusive] is true.T.minm(lowerBound, {exclusive = false}); // Ensures the value is not less than [lowerBound], exclusive if [exclusive] is true.T.clampAtMin(lowerBound); // Ensures the value is not below [lowerBound].T.clampAtMax(upperBound); // Ensures the value does not exceed [upperBound].num.orZero; // Returns this value or 0 if null.num.orOne; // Returns this value or 1 if null.num.or(value); // Returns this value or [value] if null. Utility conversion double.isWhole; // Checks if the value is a whole number.double.roundToPrecision(nthPosition); // Rounds the value to [precision] decimal places.bool.isCloseTo(other, {precision = 1.0e-8}); // Checks if the value is close to [other] within [precision].double.randomDouble({max}); // Generates a random double between 0.0 (inclusive) and 1.0 (exclusive).int Duration.inYears; // Returns the number of whole years spanned by this [Duration].bool Duration.isInYears; // Returns `true` if the [Duration] is equal to or longer than one year.int Duration.absoluteSeconds; // Returns the number of seconds remaining after accounting for whole minutes.void Map.operator entry); // Inserts a [MapEntry] into the map using the `String Map.toJson(); // Converts the map into a JSON string. For more information, check out the below link

Rating and Feedback Collector
Introduction User feedback collection cannot be overemphasized, therefore, if an app is to grow in both quality and satisfaction, The package offers a developer versatile solutions into making bars rated with icons, emojis, and even custom images. Further, this allows dynamic feedback alerts, hence allowing the user to include as much detail in their feedback as possible and rate your app. This will walk you through the setup and usage of this package, hence you can make full use of its features. Key Features Custom Icon Rating: Use any icon to represent rating units. Smiley Emojis Rating: Default emoji images to express ratings. Custom Image Rating: Use your custom images for ratings. Feedback Alert Box for Low Ratings: Prompt users to provide feedback if they rate low. Redirect to Store for High Ratings: Redirect users to the app store for a review if they rate high. Customizable UI & Contents: Fully customizable to fit your app’s theme. Submission Callback: Get feedback data with a callback function. Installation First, add the rating_and_feedback_collector package to your pubspec.yaml file: dependencies: rating_and_feedback_collector: ^0.0.2 Then, run pub get to fetch the package.Importing the PackageNext, import the package into your Dart file: import 'package:rating_and_feedback_collector/rating_and_feedback_collector.dart'; Usage Here are examples of how to use the package’s main features: Rating Bar with Icons The RatingBar widget allows you to use icons to represent ratings. You can customize the icons, their size, colors, and whether half ratings are allowed. double _rating = 0.0;RatingBar( iconSize: 40, // Size of the rating icons allowHalfRating: true, // Allows selection of half ratings filledIcon: Icons.star, // Icon for a filled rating unit halfFilledIcon: Icons.star_half, // Icon for a half-filled rating unit emptyIcon: Icons.star_border, // Icon for an empty rating unit filledColor: Colors.amber, // Color of filled rating units emptyColor: Colors.grey, // Color of empty rating units currentRating: _rating, // Set initial rating value onRatingChanged: (rating) { // Callback triggered when the rating is changed setState(() { _rating = rating; }); },), Rating Bar with Emoji Images The RatingBarEmoji widget uses default emoji images to represent ratings. double _rating = 0.0;RatingBarEmoji( imageSize: 45, // Size of image in the rating bar currentRating: _rating, // Set initial rating value onRatingChanged: (rating) { // Callback triggered when the rating is changed setState(() { _rating = rating; }); },), Rating Bar with Custom Images The RatingBarCustomImage widget allows you to use custom images for different rating levels. double _rating = 0.0;RatingBarCustomImage( imageSize: 45, // Size of image in the rating bar currentRating: _rating, // Set initial rating value activeImages: const [ AssetImage('assets/Images/ic_angry.png'), AssetImage('assets/Images/ic_sad.png'), AssetImage('assets/Images/ic_neutral.png'), AssetImage('assets/Images/ic_happy.png'), AssetImage('assets/Images/ic_excellent.png'), ], deActiveImages: const [ AssetImage('assets/Images/ic_angryDisable.png'), AssetImage('assets/Images/ic_sadDisable.png'), AssetImage('assets/Images/ic_neutralDisable.png'), AssetImage('assets/Images/ic_happyDisable.png'), AssetImage('assets/Images/ic_excellentDisable.png'), ], onRatingChanged: (rating) { // Callback triggered when the rating is changed setState(() { _rating = rating; }); },), Customization Properties The package offers various properties to customize the rating bar and feedback dialog: currentRating (double): Set initial rating value filledIcon (only for RatingBar) (IconData?): Icon for a filled rating unit halfFilledIcon (only for RatingBar) (IconData?): Icon for a half-filled rating unit emptyIcon (only for RatingBar) (IconData?): Icon for an empty rating unit filledColor (only for RatingBar) (Color?): Color of filled rating units emptyColor (only for RatingBar) (Color?): Color of empty rating units iconSize (double?): Size of the rating icons onRatingChanged (Function(double)): Callback triggered when the rating is changed allowHalfRating (only for RatingBar) (bool?): Allows selection of half ratings isGoogleFont (bool?): Set to true for using Google fonts fontFamilyName (String?): Custom font family name or Google font family name showFeedbackForRatingsLessThan (double?): Threshold rating value below which feedback box is shown feedbackBoxTitle (String?): Title for the feedback box lowRatingFeedbackTitle (String?): Title for feedback options in the low rating feedback box lowRatingFeedback (List?): List of feedback strings for low ratings showDescriptionInput (bool?): Option to show input box for user descriptions in the feedback dialog descriptionTitle (String?): Title for the description input box in the feedback dialog descriptionPlaceHolder (String?): Placeholder text for the description input box descriptionCharacterLimit (int?): Character limit for the description input submitButtonTitle (String?): Title for the submit button in the feedback dialog onSubmitTap (Function(selectedFeedback, description)): Callback function triggered on submission of feedback showRedirectToStoreForRatingsGreaterThan (double?): Threshold rating value above which the app redirects to the store for a review androidPackageName (String?): Android package name for the app, used in the store redirect iosBundleId (String?): iOS bundle ID for the app, used in the store redirect innerWidgetsBorderRadius (double?): Border radius for the feedback dialog widgets alertDialogBorderRadius (double?): Border radius for the feedback dialog Conclusion Rating_and_feedback_collector Package is the optimal solution for adding highly flexible rating bars and in-app feedback alerts into your Flutter app.By incorporating this package you can raise user’s interest, collect useful feedback and eventually boost your app’s ratings in the store. Include this package into your app and enjoy its flexible and user-friendly elements.

Islamic Hijri Calendar Package
Introduction Introducing our Islamic Hijri Calendar Package for displaying most fully featured dates in Arabic and English numerals. In this solution, customers can easily notice the month’s name in Hijri, with a year and move months without any hassle. Today, I am going to introduce the Islamic Hijri Calendar Package, which is a versatile, easy-to-use Flutter package that has the ability to show both the Islamic Hijri and the Gregorian Calendars in your Flutter apps. Key Features Dual Calendar View: Toggle between the Hijri and Gregorian calendars effortlessly.Customizable Appearance: Adjust the border colors, text colors, background colors, and font styles to match your app’s theme.Google Fonts Support: Use Google Fonts to ensure your calendar looks modern and clean.Date Selection Callbacks: Get the selected date in both Gregorian and Hijri formats.Date Adjustment: Adjust the Hijri calendar by a certain number of days as needed.Disable Out-of-Month Dates: Show or hide dates that are not part of the current month. Installation First, add the package to your `pubspec.yaml`: dependencies: islamic_hijri_calendar: ^1.0.0 Usage Here’s how you can integrate the Islamic Hijri Calendar Package into your Flutter app: import 'package:flutter/material.dart';import 'package:islamic_hijri_calendar/islamic_hijri_calendar.dart';void main() { runApp(MyApp());}class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( colorScheme: ColorScheme.fromSwatch().copyWith( primary: Colors.blue, onBackground: Colors.black, background: Colors.white, ), ), home: Scaffold( appBar: AppBar( title: Text('Islamic Hijri Calendar'), ), body: Center( child: IslamicHijriCalendar( isHijriView: true, highlightBorder: Theme.of(context).colorScheme.primary, defaultBorder: Theme.of(context).colorScheme.onBackground.withOpacity(.1), highlightTextColor: Theme.of(context).colorScheme.background, defaultTextColor: Theme.of(context).colorScheme.onBackground, defaultBackColor: Theme.of(context).colorScheme.background, adjustmentValue: 0, isGoogleFont: true, fontFamilyName: "Lato", getSelectedEnglishDate: (selectedDate) { print("English Date : $selectedDate"); }, getSelectedHijriDate: (selectedDate) { print("Hijri Date : $selectedDate"); }, isDisablePreviousNextMonthDates: true, ), ), ), ); }} Customization Options Dual Calendar View: The `isHijriView` property allows users to toggle between viewing the Hijri calendar and the Gregorian calendar. isHijriView: true, // Show Hijri calendar Appearance Customization: Customize the appearance of the calendar using the following properties: highlightBorder: Sets the border color for the selected date.defaultBorder: Sets the border color for other dates.highlightTextColor: Sets the text color for today’s date.defaultTextColor: Sets the text color for other dates.defaultBackColor: Sets the background color for dates. highlightBorder: Theme.of(context).colorScheme.primary,defaultBorder: Theme.of(context).colorScheme.onBackground.withOpacity(.1),highlightTextColor: Theme.of(context).colorScheme.background,defaultTextColor: Theme.of(context).colorScheme.onBackground,defaultBackColor: Theme.of(context).colorScheme.background, Google Fonts: Use Google Fonts to enhance the appearance of your calendar: isGoogleFont: true,fontFamilyName: "Lato", Date Selection Callbacks: Capture the selected date in both Gregorian and Hijri formats using these callbacks: getSelectedEnglishDate: (selectedDate) { print("English Date : $selectedDate");},getSelectedHijriDate: (selectedDate) { print("Hijri Date : $selectedDate");}, Date Adjustment: Adjust the Hijri calendar dates by a specific value: adjustmentValue: 0, // No adjustmen Disable Previous/Next Month Dates: Decide whether to show or hide dates from previous or next months: isDisablePreviousNextMonthDates: true, // Disable dates not in the current month Conclusion: There is a calendar widget for Muslim users available for Flutter apps. This widget shows dates according to the Islamic Hijri Calendar with the familiar Gregorian calendar. This widget is pretty easy to set up in your app and has some appearance customization. It will help any Flutter app that is specifically targeted to engage Muslim users. For more information, you can check it out at Pub.dev
Want to Work Together?
We build products, not just code. Tell us about your idea and we'll get back to you within 24 hours.