flutter_cia 1.0.1 copy "flutter_cia: ^1.0.1" to clipboard
flutter_cia: ^1.0.1 copied to clipboard

CIA Authentication SDK for Flutter - Secure login, registration, and organization token exchange

example/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_cia/flutter_cia.dart';
import 'package:provider/provider.dart';

/// Example app demonstrating flutter_cia SDK usage
void main() {
  runApp(const CIAExampleApp());
}

class CIAExampleApp extends StatelessWidget {
  const CIAExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    // Wrap with CIAAuthProvider for auth state management
    return CIAAuthProvider(
      baseUrl: 'https://cia.mn/api/v1', // Your CIA server URL with API version
      child: MaterialApp(
        title: 'CIA Auth Example',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
          useMaterial3: true,
        ),
        home: const AuthWrapper(),
      ),
    );
  }
}

/// Wrapper that handles auth state routing
class AuthWrapper extends StatelessWidget {
  const AuthWrapper({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer<CIAAuthState>(
      builder: (context, authState, _) {
        // Show appropriate screen based on auth status
        switch (authState.status) {
          case CIAAuthStatus.initializing:
            return const _LoadingScreen();
          
          case CIAAuthStatus.unauthenticated:
          case CIAAuthStatus.error:
            return const AuthNavigator();
          
          case CIAAuthStatus.pendingVerification:
            return CIAVerificationScreen(
              verificationType: authState.verificationType,
              phone: authState.pendingVerificationData?['phone'],
              branding: _getBranding(),
              onVerificationSuccess: () {
                // Navigation handled automatically by auth state change
              },
              onCancel: () async {
                await authState.cancelVerification();
              },
            );
          
          case CIAAuthStatus.authenticated:
            return const HomeScreen();
        }
      },
    );
  }
}

/// Auth screens navigator (login/register)
class AuthNavigator extends StatefulWidget {
  const AuthNavigator({super.key});

  @override
  State<AuthNavigator> createState() => _AuthNavigatorState();
}

class _AuthNavigatorState extends State<AuthNavigator> {
  bool _showLogin = true;

  @override
  Widget build(BuildContext context) {
    if (_showLogin) {
      return CIALoginScreen(
        branding: _getBranding(),
        enablePhoneLogin: true,
        onLoginSuccess: () {
          // Navigation handled by auth state change
        },
        onRegisterTap: () => setState(() => _showLogin = false),
        onForgotPasswordTap: () {
          // Navigate to forgot password screen
          _showForgotPasswordDialog(context);
        },
      );
    } else {
      return CIARegisterScreen(
        branding: _getBranding(),
        requirePhone: false,
        onRegisterSuccess: () {
          // Navigation handled by auth state change
        },
        onLoginTap: () => setState(() => _showLogin = true),
      );
    }
  }

  void _showForgotPasswordDialog(BuildContext context) {
    final emailController = TextEditingController();
    
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Reset Password'),
        content: TextField(
          controller: emailController,
          decoration: const InputDecoration(
            labelText: 'Email',
            hintText: 'Enter your email',
          ),
          keyboardType: TextInputType.emailAddress,
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () async {
              final authState = context.read<CIAAuthState>();
              final success = await authState.requestPasswordReset(
                email: emailController.text.trim(),
              );
              if (context.mounted) {
                Navigator.pop(context);
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text(
                      success
                          ? 'Password reset email sent!'
                          : authState.errorMessage ?? 'Failed to send reset email',
                    ),
                  ),
                );
              }
            },
            child: const Text('Send Reset Link'),
          ),
        ],
      ),
    );
  }
}

/// Home screen after authentication
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final authState = context.watch<CIAAuthState>();
    final user = authState.user;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
        actions: [
          IconButton(
            icon: const Icon(Icons.logout),
            onPressed: () async {
              await authState.logout();
            },
          ),
        ],
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              // User info card
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Welcome!',
                        style: TextStyle(
                          fontSize: 24,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 8),
                      Text('Email: ${user?.email ?? 'N/A'}'),
                      if (user?.name != null)
                        Text('Name: ${user?.displayName}'),
                      if (user?.phone != null)
                        Text('Phone: ${user?.phone}'),
                      const SizedBox(height: 8),
                      Row(
                        children: [
                          Icon(
                            user?.isVerified == true
                                ? Icons.verified
                                : Icons.warning,
                            color: user?.isVerified == true
                                ? Colors.green
                                : Colors.orange,
                            size: 16,
                          ),
                          const SizedBox(width: 4),
                          Text(
                            user?.isVerified == true
                                ? 'Verified'
                                : 'Not Verified',
                            style: TextStyle(
                              color: user?.isVerified == true
                                  ? Colors.green
                                  : Colors.orange,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),

              // Organizations button
              ElevatedButton.icon(
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (_) => ChangeNotifierProvider.value(
                        value: authState,
                        child: CIAOrgSelectorScreen(
                          branding: _getBranding(),
                          showExchangeCodeOption: true,
                          onOrgSelected: (org) {
                            Navigator.pop(context);
                            ScaffoldMessenger.of(context).showSnackBar(
                              SnackBar(
                                content: Text('Selected: ${org.name}'),
                              ),
                            );
                          },
                        ),
                      ),
                    ),
                  );
                },
                icon: const Icon(Icons.business),
                label: const Text('My Organizations'),
              ),
              const SizedBox(height: 12),

              // Profile button
              OutlinedButton.icon(
                onPressed: () {
                  _showProfileDialog(context, authState);
                },
                icon: const Icon(Icons.person),
                label: const Text('Edit Profile'),
              ),
              const SizedBox(height: 12),

              // Change password button
              OutlinedButton.icon(
                onPressed: () {
                  _showChangePasswordDialog(context, authState);
                },
                icon: const Icon(Icons.lock),
                label: const Text('Change Password'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _showProfileDialog(BuildContext context, CIAAuthState authState) {
    final user = authState.user;
    final nameController = TextEditingController(text: user?.name);
    final phoneController = TextEditingController(text: user?.phone);

    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Edit Profile'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextField(
              controller: nameController,
              decoration: const InputDecoration(labelText: 'Name'),
            ),
            const SizedBox(height: 8),
            TextField(
              controller: phoneController,
              decoration: const InputDecoration(labelText: 'Phone'),
              keyboardType: TextInputType.phone,
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () async {
              final success = await authState.updateProfile(
                name: nameController.text.trim(),
                phone: phoneController.text.trim(),
              );
              if (context.mounted) {
                Navigator.pop(context);
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text(
                      success ? 'Profile updated!' : authState.errorMessage ?? 'Failed',
                    ),
                  ),
                );
              }
            },
            child: const Text('Save'),
          ),
        ],
      ),
    );
  }

  void _showChangePasswordDialog(BuildContext context, CIAAuthState authState) {
    final currentPasswordController = TextEditingController();
    final newPasswordController = TextEditingController();

    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Change Password'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextField(
              controller: currentPasswordController,
              decoration: const InputDecoration(labelText: 'Current Password'),
              obscureText: true,
            ),
            const SizedBox(height: 8),
            TextField(
              controller: newPasswordController,
              decoration: const InputDecoration(labelText: 'New Password'),
              obscureText: true,
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () async {
              final success = await authState.changePassword(
                currentPassword: currentPasswordController.text,
                newPassword: newPasswordController.text,
              );
              if (context.mounted) {
                Navigator.pop(context);
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text(
                      success ? 'Password changed!' : authState.errorMessage ?? 'Failed',
                    ),
                  ),
                );
              }
            },
            child: const Text('Change'),
          ),
        ],
      ),
    );
  }
}

/// Loading screen
class _LoadingScreen extends StatelessWidget {
  const _LoadingScreen();

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CircularProgressIndicator(),
            SizedBox(height: 16),
            Text('Loading...'),
          ],
        ),
      ),
    );
  }
}

/// Get branding config (customize for your app)
CIABrandingConfig _getBranding() {
  return const CIABrandingConfig(
    appName: 'My App',
    // logoUrl: 'https://your-domain.com/logo.png',
    primaryColor: Color(0xFF2563EB), // Blue
    showPoweredByCIA: true,
  );
}
0
likes
155
points
180
downloads

Publisher

unverified uploader

Weekly Downloads

CIA Authentication SDK for Flutter - Secure login, registration, and organization token exchange

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

crypto, dio, flutter, flutter_secure_storage, jwt_decoder, provider, url_launcher

More

Packages that depend on flutter_cia